├── .bazelignore ├── .bazelrc ├── .bazelversion ├── .bcr ├── config.yml ├── metadata.template.json ├── patches │ └── no-warnings-as-errors.patch ├── presubmit.yml └── source.template.json ├── .buildkite └── pipeline.yml ├── .dockerignore ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── proposal.md │ └── rule-request.md ├── actions │ ├── bazel-linux-build │ │ └── action.yml │ └── run-make │ │ └── action.yml ├── dependabot.yml ├── plugins-sync.yml └── workflows │ ├── actor-credentials.yml │ ├── build.yml │ ├── docker.yml │ ├── docs.yml │ ├── lint.yml │ ├── plugins-sync.yml │ ├── post-release.yml │ ├── release.yml │ ├── stale-issues.yml │ └── test.yml ├── .gitignore ├── .jazzy.yaml ├── .markdownlint.yml ├── .pre-commit-hooks.yaml ├── .ruby-version ├── .spi.yml ├── .swiftlint.yml ├── BUILD ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dangerfile ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── MODULE.bazel ├── Makefile ├── Package.resolved ├── Package.swift ├── Plugins ├── SwiftLintBuildToolPlugin │ ├── Path+Helpers.swift │ ├── SwiftLintBuildToolPlugin.swift │ └── SwiftLintBuildToolPluginError.swift └── SwiftLintCommandPlugin │ ├── CommandContext.swift │ └── SwiftLintCommandPlugin.swift ├── README.md ├── README_CN.md ├── README_KR.md ├── Rules.md ├── Source ├── DyldWarningWorkaround │ ├── DyldWarningWorkaround.c │ └── include │ │ └── objc_dupclass.h ├── SwiftLintBuiltInRules │ ├── Exports.swift │ ├── Helpers │ │ └── LegacyFunctionRuleHelper.swift │ ├── Models │ │ ├── BuiltInRules.swift │ │ └── ImportUsage.swift │ └── Rules │ │ ├── Idiomatic │ │ ├── AnonymousArgumentInMultilineClosureRule.swift │ │ ├── BlockBasedKVORule.swift │ │ ├── ConvenienceTypeRule.swift │ │ ├── DiscouragedAssertRule.swift │ │ ├── DiscouragedNoneNameRule.swift │ │ ├── DiscouragedObjectLiteralRule.swift │ │ ├── DiscouragedOptionalBooleanRule.swift │ │ ├── DiscouragedOptionalBooleanRuleExamples.swift │ │ ├── DiscouragedOptionalCollectionExamples.swift │ │ ├── DiscouragedOptionalCollectionRule.swift │ │ ├── DuplicateImportsRule.swift │ │ ├── DuplicateImportsRuleExamples.swift │ │ ├── ExplicitACLRule.swift │ │ ├── ExplicitEnumRawValueRule.swift │ │ ├── ExplicitInitRule.swift │ │ ├── ExplicitTopLevelACLRule.swift │ │ ├── ExplicitTypeInterfaceRule.swift │ │ ├── ExtensionAccessModifierRule.swift │ │ ├── FallthroughRule.swift │ │ ├── FatalErrorMessageRule.swift │ │ ├── FileNameNoSpaceRule.swift │ │ ├── FileNameRule.swift │ │ ├── ForWhereRule.swift │ │ ├── ForceCastRule.swift │ │ ├── ForceTryRule.swift │ │ ├── ForceUnwrappingRule.swift │ │ ├── FunctionDefaultParameterAtEndRule.swift │ │ ├── GenericTypeNameRule.swift │ │ ├── ImplicitlyUnwrappedOptionalRule.swift │ │ ├── IsDisjointRule.swift │ │ ├── JoinedDefaultParameterRule.swift │ │ ├── LegacyCGGeometryFunctionsRule.swift │ │ ├── LegacyConstantRule.swift │ │ ├── LegacyConstantRuleExamples.swift │ │ ├── LegacyConstructorRule.swift │ │ ├── LegacyHashingRule.swift │ │ ├── LegacyMultipleRule.swift │ │ ├── LegacyNSGeometryFunctionsRule.swift │ │ ├── LegacyObjcTypeRule.swift │ │ ├── LegacyRandomRule.swift │ │ ├── NimbleOperatorRule.swift │ │ ├── NoEmptyBlockRule.swift │ │ ├── NoExtensionAccessModifierRule.swift │ │ ├── NoFallthroughOnlyRule.swift │ │ ├── NoFallthroughOnlyRuleExamples.swift │ │ ├── NoGroupingExtensionRule.swift │ │ ├── NoMagicNumbersRule.swift │ │ ├── ObjectLiteralRule.swift │ │ ├── OneDeclarationPerFileRule.swift │ │ ├── PatternMatchingKeywordsRule.swift │ │ ├── PreferConditionListRule.swift │ │ ├── PreferKeyPathRule.swift │ │ ├── PreferNimbleRule.swift │ │ ├── PreferTypeCheckingRule.swift │ │ ├── PreferZeroOverExplicitInitRule.swift │ │ ├── PrivateOverFilePrivateRule.swift │ │ ├── RedundantNilCoalescingRule.swift │ │ ├── RedundantObjcAttributeRule.swift │ │ ├── RedundantObjcAttributeRuleExamples.swift │ │ ├── RedundantOptionalInitializationRule.swift │ │ ├── RedundantSetAccessControlRule.swift │ │ ├── RedundantStringEnumValueRule.swift │ │ ├── RedundantTypeAnnotationRule.swift │ │ ├── RedundantVoidReturnRule.swift │ │ ├── ReturnValueFromVoidFunctionRule.swift │ │ ├── ReturnValueFromVoidFunctionRuleExamples.swift │ │ ├── ShorthandOptionalBindingRule.swift │ │ ├── StaticOperatorRule.swift │ │ ├── StaticOverFinalClassRule.swift │ │ ├── StrictFilePrivateRule.swift │ │ ├── SyntacticSugarRule.swift │ │ ├── SyntacticSugarRuleExamples.swift │ │ ├── ToggleBoolRule.swift │ │ ├── TrailingSemicolonRule.swift │ │ ├── TypeNameRule.swift │ │ ├── TypeNameRuleExamples.swift │ │ ├── UnavailableConditionRule.swift │ │ ├── UnavailableFunctionRule.swift │ │ ├── UnneededBreakInSwitchRule.swift │ │ ├── UnneededSynthesizedInitializerRule.swift │ │ ├── UnneededSynthesizedInitializerRuleExamples.swift │ │ ├── UntypedErrorInCatchRule.swift │ │ ├── UnusedEnumeratedRule.swift │ │ ├── VoidFunctionInTernaryConditionRule.swift │ │ ├── XCTFailMessageRule.swift │ │ ├── XCTSpecificMatcherRule.swift │ │ └── XCTSpecificMatcherRuleExamples.swift │ │ ├── Lint │ │ ├── AccessibilityLabelForImageRule.swift │ │ ├── AccessibilityLabelForImageRuleExamples.swift │ │ ├── AccessibilityTraitForButtonRule.swift │ │ ├── AccessibilityTraitForButtonRuleExamples.swift │ │ ├── ArrayInitRule.swift │ │ ├── AsyncWithoutAwaitRule.swift │ │ ├── AsyncWithoutAwaitRuleExamples.swift │ │ ├── BalancedXCTestLifecycleRule.swift │ │ ├── BlanketDisableCommandRule.swift │ │ ├── CaptureVariableRule.swift │ │ ├── ClassDelegateProtocolRule.swift │ │ ├── CommentSpacingRule.swift │ │ ├── CompilerProtocolInitRule.swift │ │ ├── DeploymentTargetRule.swift │ │ ├── DeploymentTargetRuleExamples.swift │ │ ├── DiscardedNotificationCenterObserverRule.swift │ │ ├── DiscouragedDirectInitRule.swift │ │ ├── DuplicateConditionsRule.swift │ │ ├── DuplicateEnumCasesRule.swift │ │ ├── DuplicatedKeyInDictionaryLiteralRule.swift │ │ ├── DynamicInlineRule.swift │ │ ├── EmptyXCTestMethodRule.swift │ │ ├── EmptyXCTestMethodRuleExamples.swift │ │ ├── ExpiringTodoRule.swift │ │ ├── IBInspectableInExtensionRule.swift │ │ ├── IdenticalOperandsRule.swift │ │ ├── InvalidSwiftLintCommandRule.swift │ │ ├── LocalDocCommentRule.swift │ │ ├── LowerACLThanParentRule.swift │ │ ├── MarkRule.swift │ │ ├── MarkRuleExamples.swift │ │ ├── MissingDocsRule.swift │ │ ├── MissingDocsRuleExamples.swift │ │ ├── NSLocalizedStringKeyRule.swift │ │ ├── NSLocalizedStringRequireBundleRule.swift │ │ ├── NSNumberInitAsFunctionReferenceRule.swift │ │ ├── NSObjectPreferIsEqualRule.swift │ │ ├── NSObjectPreferIsEqualRuleExamples.swift │ │ ├── NonOptionalStringDataConversionRule.swift │ │ ├── NotificationCenterDetachmentRule.swift │ │ ├── NotificationCenterDetachmentRuleExamples.swift │ │ ├── OptionalDataStringConversionRule.swift │ │ ├── OrphanedDocCommentRule.swift │ │ ├── OverriddenSuperCallRule.swift │ │ ├── OverrideInExtensionRule.swift │ │ ├── PeriodSpacingRule.swift │ │ ├── PrivateActionRule.swift │ │ ├── PrivateOutletRule.swift │ │ ├── PrivateSubjectRule.swift │ │ ├── PrivateSubjectRuleExamples.swift │ │ ├── PrivateSwiftUIStatePropertyRule.swift │ │ ├── PrivateSwiftUIStatePropertyRuleExamples.swift │ │ ├── PrivateUnitTestRule.swift │ │ ├── ProhibitedInterfaceBuilderRule.swift │ │ ├── ProhibitedSuperRule.swift │ │ ├── QuickDiscouragedCallRule.swift │ │ ├── QuickDiscouragedCallRuleExamples.swift │ │ ├── QuickDiscouragedFocusedTestRule.swift │ │ ├── QuickDiscouragedFocusedTestRuleExamples.swift │ │ ├── QuickDiscouragedPendingTestRule.swift │ │ ├── QuickDiscouragedPendingTestRuleExamples.swift │ │ ├── RawValueForCamelCasedCodableEnumRule.swift │ │ ├── RedundantSendableRule.swift │ │ ├── RequiredDeinitRule.swift │ │ ├── RequiredEnumCaseRule.swift │ │ ├── SelfInPropertyInitializationRule.swift │ │ ├── StrongIBOutletRule.swift │ │ ├── TestCaseAccessibilityRule.swift │ │ ├── TestCaseAccessibilityRuleExamples.swift │ │ ├── TodoRule.swift │ │ ├── TypesafeArrayInitRule.swift │ │ ├── UnhandledThrowingTaskRule.swift │ │ ├── UnneededOverrideRule.swift │ │ ├── UnneededOverrideRuleExamples.swift │ │ ├── UnownedVariableCaptureRule.swift │ │ ├── UnusedClosureParameterRule.swift │ │ ├── UnusedClosureParameterRuleExamples.swift │ │ ├── UnusedControlFlowLabelRule.swift │ │ ├── UnusedDeclarationRule.swift │ │ ├── UnusedDeclarationRuleExamples.swift │ │ ├── UnusedImportRule.swift │ │ ├── UnusedImportRuleExamples.swift │ │ ├── UnusedParameterRule.swift │ │ ├── UnusedSetterValueRule.swift │ │ ├── ValidIBInspectableRule.swift │ │ ├── WeakDelegateRule.swift │ │ └── YodaConditionRule.swift │ │ ├── Metrics │ │ ├── ClosureBodyLengthRule.swift │ │ ├── ClosureBodyLengthRuleExamples.swift │ │ ├── CyclomaticComplexityRule.swift │ │ ├── EnumCaseAssociatedValuesLengthRule.swift │ │ ├── FileLengthRule.swift │ │ ├── FunctionBodyLengthRule.swift │ │ ├── FunctionParameterCountRule.swift │ │ ├── LargeTupleRule.swift │ │ ├── LineLengthRule.swift │ │ ├── NestingRule.swift │ │ ├── NestingRuleExamples.swift │ │ └── TypeBodyLengthRule.swift │ │ ├── Performance │ │ ├── ContainsOverFilterCountRule.swift │ │ ├── ContainsOverFilterIsEmptyRule.swift │ │ ├── ContainsOverFirstNotNilRule.swift │ │ ├── ContainsOverRangeNilComparisonRule.swift │ │ ├── EmptyCollectionLiteralRule.swift │ │ ├── EmptyCountRule.swift │ │ ├── EmptyStringRule.swift │ │ ├── FinalTestCaseRule.swift │ │ ├── FirstWhereRule.swift │ │ ├── FlatMapOverMapReduceRule.swift │ │ ├── LastWhereRule.swift │ │ ├── ReduceBooleanRule.swift │ │ ├── ReduceIntoRule.swift │ │ └── SortedFirstLastRule.swift │ │ ├── RuleConfigurations │ │ ├── AttributesConfiguration.swift │ │ ├── BlanketDisableCommandConfiguration.swift │ │ ├── CollectionAlignmentConfiguration.swift │ │ ├── ColonConfiguration.swift │ │ ├── ComputedAccessorsOrderConfiguration.swift │ │ ├── ConditionalReturnsOnNewlineConfiguration.swift │ │ ├── CyclomaticComplexityConfiguration.swift │ │ ├── DeploymentTargetConfiguration.swift │ │ ├── DiscouragedDirectInitConfiguration.swift │ │ ├── EmptyCountConfiguration.swift │ │ ├── ExpiringTodoConfiguration.swift │ │ ├── ExplicitInitConfiguration.swift │ │ ├── ExplicitTypeInterfaceConfiguration.swift │ │ ├── FileHeaderConfiguration.swift │ │ ├── FileLengthConfiguration.swift │ │ ├── FileNameConfiguration.swift │ │ ├── FileNameNoSpaceConfiguration.swift │ │ ├── FileTypesOrderConfiguration.swift │ │ ├── ForWhereConfiguration.swift │ │ ├── FunctionDefaultParameterAtEndConfiguration.swift │ │ ├── FunctionParameterCountConfiguration.swift │ │ ├── IdentifierNameConfiguration.swift │ │ ├── ImplicitReturnConfiguration.swift │ │ ├── ImplicitlyUnwrappedOptionalConfiguration.swift │ │ ├── InclusiveLanguageConfiguration.swift │ │ ├── IndentationWidthConfiguration.swift │ │ ├── LegacyObjcTypeConfiguration.swift │ │ ├── LineLengthConfiguration.swift │ │ ├── MissingDocsConfiguration.swift │ │ ├── ModifierOrderConfiguration.swift │ │ ├── MultilineArgumentsConfiguration.swift │ │ ├── MultilineParametersConfiguration.swift │ │ ├── NameConfiguration.swift │ │ ├── NestingConfiguration.swift │ │ ├── NoEmptyBlockConfiguration.swift │ │ ├── NoMagicNumbersConfiguration.swift │ │ ├── NonOverridableClassDeclarationConfiguration.swift │ │ ├── NumberSeparatorConfiguration.swift │ │ ├── ObjectLiteralConfiguration.swift │ │ ├── OpeningBraceConfiguration.swift │ │ ├── OperatorUsageWhitespaceConfiguration.swift │ │ ├── OverriddenSuperCallConfiguration.swift │ │ ├── PreferKeyPathConfiguration.swift │ │ ├── PrefixedTopLevelConstantConfiguration.swift │ │ ├── PrivateOutletConfiguration.swift │ │ ├── PrivateOverFilePrivateConfiguration.swift │ │ ├── ProhibitedSuperConfiguration.swift │ │ ├── RedundantDiscardableLetConfiguration.swift │ │ ├── RedundantSendableConfiguration.swift │ │ ├── RedundantTypeAnnotationConfiguration.swift │ │ ├── RedundantVoidReturnConfiguration.swift │ │ ├── RequiredEnumCaseConfiguration.swift │ │ ├── SelfBindingConfiguration.swift │ │ ├── ShorthandArgumentConfiguration.swift │ │ ├── SortedImportsConfiguration.swift │ │ ├── StatementPositionConfiguration.swift │ │ ├── SwitchCaseAlignmentConfiguration.swift │ │ ├── TestCaseAccessibilityConfiguration.swift │ │ ├── TodoConfiguration.swift │ │ ├── TrailingClosureConfiguration.swift │ │ ├── TrailingCommaConfiguration.swift │ │ ├── TrailingWhitespaceConfiguration.swift │ │ ├── TypeBodyLengthConfiguration.swift │ │ ├── TypeContentsOrderConfiguration.swift │ │ ├── TypeNameConfiguration.swift │ │ ├── UnitTestConfiguration.swift │ │ ├── UnneededOverrideRuleConfiguration.swift │ │ ├── UnusedDeclarationConfiguration.swift │ │ ├── UnusedImportConfiguration.swift │ │ ├── UnusedOptionalBindingConfiguration.swift │ │ ├── VerticalWhitespaceClosingBracesConfiguration.swift │ │ ├── VerticalWhitespaceConfiguration.swift │ │ └── XCTSpecificMatcherConfiguration.swift │ │ └── Style │ │ ├── AttributeNameSpacingRule.swift │ │ ├── AttributesRule.swift │ │ ├── AttributesRuleExamples.swift │ │ ├── ClosingBraceRule.swift │ │ ├── ClosureEndIndentationRule.swift │ │ ├── ClosureEndIndentationRuleExamples.swift │ │ ├── ClosureParameterPositionRule.swift │ │ ├── ClosureSpacingRule.swift │ │ ├── CollectionAlignmentRule.swift │ │ ├── ColonRule.swift │ │ ├── ColonRuleExamples.swift │ │ ├── CommaInheritanceRule.swift │ │ ├── CommaRule.swift │ │ ├── ComputedAccessorsOrderRule.swift │ │ ├── ComputedAccessorsOrderRuleExamples.swift │ │ ├── ConditionalReturnsOnNewlineRule.swift │ │ ├── ContrastedOpeningBraceRule.swift │ │ ├── ContrastedOpeningBraceRuleExamples.swift │ │ ├── ControlStatementRule.swift │ │ ├── DirectReturnRule.swift │ │ ├── EmptyEnumArgumentsRule.swift │ │ ├── EmptyParametersRule.swift │ │ ├── EmptyParenthesesWithTrailingClosureRule.swift │ │ ├── ExplicitSelfRule.swift │ │ ├── ExplicitSelfRuleExamples.swift │ │ ├── FileHeaderRule.swift │ │ ├── FileTypesOrderRule.swift │ │ ├── FileTypesOrderRuleExamples.swift │ │ ├── IdentifierNameRule.swift │ │ ├── IdentifierNameRuleExamples.swift │ │ ├── ImplicitGetterRule.swift │ │ ├── ImplicitGetterRuleExamples.swift │ │ ├── ImplicitReturnRule.swift │ │ ├── ImplicitReturnRuleExamples.swift │ │ ├── InclusiveLanguageRule.swift │ │ ├── InclusiveLanguageRuleExamples.swift │ │ ├── IndentationWidthRule.swift │ │ ├── LeadingWhitespaceRule.swift │ │ ├── LetVarWhitespaceRule.swift │ │ ├── LiteralExpressionEndIndentationRule.swift │ │ ├── ModifierOrderRule.swift │ │ ├── ModifierOrderRuleExamples.swift │ │ ├── MultilineArgumentsBracketsRule.swift │ │ ├── MultilineArgumentsRule.swift │ │ ├── MultilineArgumentsRuleExamples.swift │ │ ├── MultilineFunctionChainsRule.swift │ │ ├── MultilineLiteralBracketsRule.swift │ │ ├── MultilineParametersBracketsRule.swift │ │ ├── MultilineParametersRule.swift │ │ ├── MultilineParametersRuleExamples.swift │ │ ├── MultipleClosuresWithTrailingClosureRule.swift │ │ ├── NoSpaceInMethodCallRule.swift │ │ ├── NonOverridableClassDeclarationRule.swift │ │ ├── NumberSeparatorRule.swift │ │ ├── NumberSeparatorRuleExamples.swift │ │ ├── OpeningBraceRule.swift │ │ ├── OpeningBraceRuleExamples.swift │ │ ├── OperatorFunctionWhitespaceRule.swift │ │ ├── OperatorUsageWhitespaceRule.swift │ │ ├── OperatorUsageWhitespaceRuleExamples.swift │ │ ├── OptionalEnumCaseMatchingRule.swift │ │ ├── PreferSelfInStaticReferencesRule.swift │ │ ├── PreferSelfInStaticReferencesRuleExamples.swift │ │ ├── PreferSelfTypeOverTypeOfSelfRule.swift │ │ ├── PrefixedTopLevelConstantRule.swift │ │ ├── ProtocolPropertyAccessorsOrderRule.swift │ │ ├── RedundantDiscardableLetRule.swift │ │ ├── RedundantSelfInClosureRule.swift │ │ ├── RedundantSelfInClosureRuleExamples.swift │ │ ├── ReturnArrowWhitespaceRule.swift │ │ ├── SelfBindingRule.swift │ │ ├── ShorthandArgumentRule.swift │ │ ├── ShorthandOperatorRule.swift │ │ ├── SingleTestClassRule.swift │ │ ├── SortedEnumCasesRule.swift │ │ ├── SortedImportsRule.swift │ │ ├── SortedImportsRuleExamples.swift │ │ ├── StatementPositionRule.swift │ │ ├── SuperfluousElseRule.swift │ │ ├── SwitchCaseAlignmentRule.swift │ │ ├── SwitchCaseOnNewlineRule.swift │ │ ├── TrailingClosureRule.swift │ │ ├── TrailingCommaRule.swift │ │ ├── TrailingNewlineRule.swift │ │ ├── TrailingWhitespaceRule.swift │ │ ├── TypeContentsOrderRule.swift │ │ ├── TypeContentsOrderRuleExamples.swift │ │ ├── UnneededParenthesesInClosureArgumentRule.swift │ │ ├── UnusedOptionalBindingRule.swift │ │ ├── VerticalParameterAlignmentOnCallRule.swift │ │ ├── VerticalParameterAlignmentRule.swift │ │ ├── VerticalParameterAlignmentRuleExamples.swift │ │ ├── VerticalWhitespaceBetweenCasesRule.swift │ │ ├── VerticalWhitespaceClosingBracesRule.swift │ │ ├── VerticalWhitespaceClosingBracesRuleExamples.swift │ │ ├── VerticalWhitespaceOpeningBracesRule.swift │ │ ├── VerticalWhitespaceRule.swift │ │ └── VoidReturnRule.swift ├── SwiftLintCore │ ├── Extensions │ │ ├── Array+SwiftLint.swift │ │ ├── ByteCount+SwiftSyntax.swift │ │ ├── Collection+Windows.swift │ │ ├── Dictionary+SwiftLint.swift │ │ ├── NSRange+SwiftLint.swift │ │ ├── NSRegularExpression+SwiftLint.swift │ │ ├── QueuedPrint.swift │ │ ├── RandomAccessCollection+Swiftlint.swift │ │ ├── Request+SwiftLint.swift │ │ ├── SourceKittenDictionary+Swiftlint.swift │ │ ├── SourceRange+SwiftLint.swift │ │ ├── String+SwiftLint.swift │ │ ├── StringView+SwiftLint.swift │ │ ├── StringView+SwiftSyntax.swift │ │ ├── SwiftDeclarationAttributeKind+Swiftlint.swift │ │ ├── SwiftDeclarationKind+SwiftLint.swift │ │ ├── SwiftLintFile+BodyLineCount.swift │ │ ├── SwiftLintFile+Cache.swift │ │ ├── SwiftLintFile+Regex.swift │ │ ├── SwiftSyntax+SwiftLint.swift │ │ ├── SyntaxClassification+isComment.swift │ │ └── SyntaxKind+SwiftLint.swift │ ├── Helpers │ │ ├── Macros.swift │ │ ├── Stack.swift │ │ └── SwiftSyntaxKindBridge.swift │ ├── Models │ │ ├── AccessControlLevel.swift │ │ ├── Baseline.swift │ │ ├── ChildOptionSeverityConfiguration.swift │ │ ├── Command.swift │ │ ├── ConfigurationRuleWrapper.swift │ │ ├── Correction.swift │ │ ├── CurrentRule.swift │ │ ├── Example.swift │ │ ├── Issue.swift │ │ ├── Location.swift │ │ ├── Region.swift │ │ ├── RuleConfigurationDescription.swift │ │ ├── RuleDescription.swift │ │ ├── RuleIdentifier.swift │ │ ├── RuleKind.swift │ │ ├── RuleList.swift │ │ ├── RuleParameter.swift │ │ ├── RuleRegistry.swift │ │ ├── RuleStorage.swift │ │ ├── SeverityConfiguration.swift │ │ ├── StyleViolation.swift │ │ ├── SwiftExpressionKind.swift │ │ ├── SwiftLintFile.swift │ │ ├── SwiftLintSyntaxMap.swift │ │ ├── SwiftLintSyntaxToken.swift │ │ ├── SwiftVersion.swift │ │ └── ViolationSeverity.swift │ ├── Protocols │ │ ├── ASTRule.swift │ │ ├── CacheDescriptionProvider.swift │ │ ├── CollectingRule.swift │ │ ├── Rule.swift │ │ ├── RuleConfiguration.swift │ │ ├── SwiftSyntaxCorrectableRule.swift │ │ └── SwiftSyntaxRule.swift │ ├── Rewriters │ │ └── CodeIndentingRewriter.swift │ ├── RuleConfigurations │ │ ├── RegexConfiguration.swift │ │ └── SeverityLevelsConfiguration.swift │ └── Visitors │ │ ├── BodyLengthVisitor.swift │ │ ├── CodeBlockVisitor.swift │ │ ├── CommandVisitor.swift │ │ ├── DeclaredIdentifiersTrackingVisitor.swift │ │ └── ViolationsSyntaxVisitor.swift ├── SwiftLintCoreMacros │ ├── RuleConfigurationMacros.swift │ ├── SwiftLintCoreMacros.swift │ └── SwiftSyntaxRule.swift ├── SwiftLintExtraRules │ ├── Exports.swift │ └── ExtraRules.swift ├── SwiftLintFramework │ ├── Benchmark.swift │ ├── CompilerArgumentsExtractor.swift │ ├── Configuration+CommandLine.swift │ ├── Configuration │ │ ├── Configuration+Cache.swift │ │ ├── Configuration+FileGraph.swift │ │ ├── Configuration+FileGraphSubtypes.swift │ │ ├── Configuration+IndentationStyle.swift │ │ ├── Configuration+LintableFiles.swift │ │ ├── Configuration+Merging.swift │ │ ├── Configuration+Parsing.swift │ │ ├── Configuration+Remote.swift │ │ ├── Configuration+RulesMode.swift │ │ ├── Configuration+RulesWrapper.swift │ │ └── Configuration.swift │ ├── Documentation │ │ ├── RuleDocumentation.swift │ │ └── RuleListDocumentation.swift │ ├── Exports.swift │ ├── Extensions │ │ ├── FileManager+SwiftLint.swift │ │ ├── String+XML.swift │ │ └── String+sha256.swift │ ├── Helpers │ │ ├── ExecutableInfo.swift │ │ ├── Glob.swift │ │ └── Reachability.swift │ ├── LintOrAnalyzeCommand.swift │ ├── LintableFilesVisitor.swift │ ├── Models │ │ ├── CustomRuleTimer.swift │ │ ├── HashableConfigurationRuleWrapperWrapper.swift │ │ ├── Linter.swift │ │ ├── LinterCache.swift │ │ ├── ReportersList.swift │ │ ├── Version.swift │ │ └── YamlParser.swift │ ├── ProcessInfo+XcodeCloud.swift │ ├── ProgressBar.swift │ ├── Reporters │ │ ├── CSVReporter.swift │ │ ├── CheckstyleReporter.swift │ │ ├── CodeClimateReporter.swift │ │ ├── EmojiReporter.swift │ │ ├── GitHubActionsLoggingReporter.swift │ │ ├── GitLabJUnitReporter.swift │ │ ├── HTMLReporter.swift │ │ ├── JSONReporter.swift │ │ ├── JUnitReporter.swift │ │ ├── MarkdownReporter.swift │ │ ├── RelativePathReporter.swift │ │ ├── Reporter.swift │ │ ├── SARIFReporter.swift │ │ ├── SonarQubeReporter.swift │ │ ├── SummaryReporter.swift │ │ └── XcodeReporter.swift │ ├── Rules │ │ ├── CoreRules.swift │ │ ├── CustomRules.swift │ │ └── SuperfluousDisableCommandRule.swift │ ├── RulesFilter.swift │ ├── Signposts.swift │ ├── SwiftLintError.swift │ ├── SwiftPMCompilationDB.swift │ └── UpdateChecker.swift ├── YamsWrapper │ └── Empty.swift ├── swiftlint-dev │ ├── Reporters+Register.swift │ ├── Rules+Register.swift │ ├── Rules+Template.swift │ └── SwiftLintDev.swift └── swiftlint │ ├── Commands │ ├── Analyze.swift │ ├── Baseline.swift │ ├── Docs.swift │ ├── GenerateDocs.swift │ ├── Lint.swift │ ├── Reporters.swift │ ├── Rules.swift │ ├── SwiftLint.swift │ └── Version.swift │ └── Common │ ├── LintOrAnalyzeArguments.swift │ └── RulesFilterOptions.swift ├── SwiftLint.podspec ├── Tests ├── BUILD ├── BuiltInRulesTests │ ├── AttributesRuleTests.swift │ ├── BlanketDisableCommandRuleTests.swift │ ├── ChildOptionSeverityConfigurationTests.swift │ ├── CollectionAlignmentRuleTests.swift │ ├── ColonRuleTests.swift │ ├── CompilerProtocolInitRuleTests.swift │ ├── ComputedAccessorsOrderRuleTests.swift │ ├── ConditionalReturnsOnNewlineRuleTests.swift │ ├── ContainsOverFirstNotNilRuleTests.swift │ ├── CyclomaticComplexityConfigurationTests.swift │ ├── CyclomaticComplexityRuleTests.swift │ ├── DeploymentTargetConfigurationTests.swift │ ├── DeploymentTargetRuleTests.swift │ ├── DiscouragedDirectInitRuleTests.swift │ ├── DiscouragedObjectLiteralRuleTests.swift │ ├── DuplicateImportsRuleTests.swift │ ├── EmptyCountRuleTests.swift │ ├── ExpiringTodoRuleTests.swift │ ├── ExplicitInitRuleTests.swift │ ├── ExplicitTypeInterfaceConfigurationTests.swift │ ├── ExplicitTypeInterfaceRuleTests.swift │ ├── FileHeaderRuleTests.swift │ ├── FileLengthRuleTests.swift │ ├── FileNameNoSpaceRuleTests.swift │ ├── FileNameRuleTests.swift │ ├── FileTypesOrderRuleTests.swift │ ├── FunctionBodyLengthRuleTests.swift │ ├── FunctionParameterCountRuleTests.swift │ ├── GenericTypeNameRuleTests.swift │ ├── IdentifierNameRuleTests.swift │ ├── ImplicitGetterRuleTests.swift │ ├── ImplicitReturnConfigurationTests.swift │ ├── ImplicitReturnRuleTests.swift │ ├── ImplicitlyUnwrappedOptionalConfigurationTests.swift │ ├── ImplicitlyUnwrappedOptionalRuleTests.swift │ ├── InclusiveLanguageRuleTests.swift │ ├── IndentationWidthRuleTests.swift │ ├── LineLengthConfigurationTests.swift │ ├── LineLengthRuleTests.swift │ ├── MissingDocsRuleTests.swift │ ├── MultilineArgumentsRuleTests.swift │ ├── MultilineParametersConfigurationTests.swift │ ├── NameConfigurationTests.swift │ ├── NestingRuleTests.swift │ ├── NoEmptyBlockConfigurationTests.swift │ ├── NumberSeparatorRuleTests.swift │ ├── ObjectLiteralRuleTests.swift │ ├── OpeningBraceRuleTests.swift │ ├── PreferKeyPathRuleTests.swift │ ├── PrefixedTopLevelConstantRuleTests.swift │ ├── PrivateOverFilePrivateRuleTests.swift │ ├── RequiredEnumCaseConfigurationTests.swift │ ├── Resources │ │ ├── FileHeaderRuleFixtures │ │ │ ├── DocumentedType.swift │ │ │ ├── FileHeaderEmpty.swift │ │ │ ├── FileNameCaseMismatch.swift │ │ │ ├── FileNameMatchingComplex.swift │ │ │ ├── FileNameMatchingSimple.swift │ │ │ ├── FileNameMismatch.swift │ │ │ └── FileNameMissing.swift │ │ ├── FileNameNoSpaceRuleFixtures │ │ │ ├── File Name.swift │ │ │ ├── File+Extension.swift │ │ │ ├── File+Test Extension.swift │ │ │ └── File.swift │ │ └── FileNameRuleFixtures │ │ │ ├── BoolExtension.swift │ │ │ ├── BoolExtensionTests.swift │ │ │ ├── BoolExtensions.swift │ │ │ ├── ExtensionBool+SwiftLint.swift │ │ │ ├── ExtensionBool.swift │ │ │ ├── ExtensionsBool.swift │ │ │ ├── LinuxMain.swift │ │ │ ├── Multiple.Levels.Deeply.Nested.MyType.swift │ │ │ ├── MyClass.swift │ │ │ ├── MyMacro.swift │ │ │ ├── MyStruct.swift │ │ │ ├── MyStructf.swift │ │ │ ├── MyType.swift │ │ │ ├── NSString+Extension.swift │ │ │ ├── Nested.MyType.swift │ │ │ ├── Notification.Name+Extension.swift │ │ │ ├── NotificationName+Extension.swift │ │ │ ├── Notification__Name+Extension.swift │ │ │ ├── SLBoolExtension.swift │ │ │ └── main.swift │ ├── StatementPositionRuleTests.swift │ ├── SwitchCaseAlignmentRuleTests.swift │ ├── TodoRuleTests.swift │ ├── TrailingClosureConfigurationTests.swift │ ├── TrailingClosureRuleTests.swift │ ├── TrailingCommaRuleTests.swift │ ├── TrailingWhitespaceRuleTests.swift │ ├── TypeBodyLengthConfigurationTests.swift │ ├── TypeBodyLengthRuleTests.swift │ ├── TypeContentsOrderRuleTests.swift │ ├── TypeNameRuleTests.swift │ ├── TypesafeArrayInitRuleTests.swift │ ├── UnneededOverrideRuleTests.swift │ ├── UnusedDeclarationConfigurationTests.swift │ ├── UnusedOptionalBindingRuleTests.swift │ ├── VerticalWhitespaceRuleTests.swift │ └── XCTSpecificMatcherRuleTests.swift ├── CLITests │ └── RulesFilterTests.swift ├── ExtraRulesTests │ └── ExtraRulesTests.swift ├── FrameworkTests │ ├── AccessControlLevelTests.swift │ ├── BaselineTests.swift │ ├── CodeIndentingRewriterTests.swift │ ├── CollectingRuleTests.swift │ ├── CommandTests.swift │ ├── ConditionallySourceKitFreeTests.swift │ ├── ConfigurationAliasesTests.swift │ ├── ConfigurationTests+Mock.swift │ ├── ConfigurationTests+MultipleConfigs.swift │ ├── ConfigurationTests.swift │ ├── CustomRulesTests.swift │ ├── DisableAllTests.swift │ ├── EmptyFileTests.swift │ ├── ExampleTests.swift │ ├── Exports.swift │ ├── ExtendedNSStringTests.swift │ ├── ExtendedStringTests.swift │ ├── GlobTests.swift │ ├── LineEndingTests.swift │ ├── LintOrAnalyzeOptionsTests.swift │ ├── LinterCacheTests.swift │ ├── ModifierOrderTests.swift │ ├── ParserDiagnosticsTests.swift │ ├── RegexConfigurationTests.swift │ ├── RegionTests.swift │ ├── ReporterTests.swift │ ├── Resources │ │ ├── CannedCSVReporterOutput.csv │ │ ├── CannedCheckstyleReporterOutput.xml │ │ ├── CannedCodeClimateReporterOutput.json │ │ ├── CannedEmojiReporterOutput.txt │ │ ├── CannedGitHubActionsLoggingReporterOutput.txt │ │ ├── CannedGitLabJUnitReporterOutput.xml │ │ ├── CannedHTMLReporterOutput.html │ │ ├── CannedJSONReporterOutput.json │ │ ├── CannedJunitReporterOutput.xml │ │ ├── CannedMarkdownReporterOutput.md │ │ ├── CannedRelativePathReporterOutput.txt │ │ ├── CannedSARIFReporterOutput.json │ │ ├── CannedSonarQubeReporterOutput.json │ │ ├── CannedSummaryReporterNoViolationsOutput.txt │ │ ├── CannedSummaryReporterOutput.txt │ │ ├── CannedXcodeReporterOutput.txt │ │ ├── ProjectMock │ │ │ ├── .swiftlint.yml │ │ │ ├── ChildConfig │ │ │ │ ├── Cycle1 │ │ │ │ │ └── .swiftlint.yml │ │ │ │ ├── Cycle2 │ │ │ │ │ ├── .swiftlint.yml │ │ │ │ │ └── child.yml │ │ │ │ ├── Cycle3 │ │ │ │ │ ├── Main │ │ │ │ │ │ ├── .swiftlint.yml │ │ │ │ │ │ ├── Folder │ │ │ │ │ │ │ └── child2.yml │ │ │ │ │ │ └── child1.yml │ │ │ │ │ └── child3.yml │ │ │ │ ├── Cycle4 │ │ │ │ │ ├── child.yml │ │ │ │ │ └── main.yml │ │ │ │ ├── Test1 │ │ │ │ │ ├── Main │ │ │ │ │ │ ├── Folder │ │ │ │ │ │ │ └── child3.yml │ │ │ │ │ │ ├── child1.yml │ │ │ │ │ │ ├── child2.yml │ │ │ │ │ │ ├── expected.yml │ │ │ │ │ │ └── main.yml │ │ │ │ │ └── child4.yml │ │ │ │ └── Test2 │ │ │ │ │ ├── child1.yml │ │ │ │ │ ├── child2.yml │ │ │ │ │ ├── expected.yml │ │ │ │ │ └── main.yml │ │ │ ├── Directory.swift │ │ │ │ └── DirectoryLevel1.swift │ │ │ ├── EmptyFolder │ │ │ │ └── .gitkeep │ │ │ ├── Level0.swift │ │ │ ├── Level1 │ │ │ │ ├── Level1.swift │ │ │ │ └── Level2 │ │ │ │ │ ├── .swiftlint.yml │ │ │ │ │ ├── Level2.swift │ │ │ │ │ ├── Level3 │ │ │ │ │ ├── .swiftlint.yml │ │ │ │ │ └── Level3.swift │ │ │ │ │ ├── custom_rules.yml │ │ │ │ │ ├── custom_rules_disabled.yml │ │ │ │ │ ├── custom_rules_only.yml │ │ │ │ │ └── custom_rules_reconfig.yml │ │ │ ├── NestedConfig │ │ │ │ └── Test │ │ │ │ │ ├── .swiftlint.yml │ │ │ │ │ ├── Main.swift │ │ │ │ │ └── Sub │ │ │ │ │ ├── .swiftlint.yml │ │ │ │ │ └── Sub.swift │ │ │ ├── ParentConfig │ │ │ │ ├── Cycle1 │ │ │ │ │ └── .swiftlint.yml │ │ │ │ ├── Cycle2 │ │ │ │ │ ├── .swiftlint.yml │ │ │ │ │ └── parent.yml │ │ │ │ ├── Cycle3 │ │ │ │ │ ├── .swiftlint.yml │ │ │ │ │ └── parent.yml │ │ │ │ ├── Test1 │ │ │ │ │ ├── expected.yml │ │ │ │ │ ├── main.yml │ │ │ │ │ ├── parent1.yml │ │ │ │ │ └── parent2.yml │ │ │ │ └── Test2 │ │ │ │ │ ├── expected.yml │ │ │ │ │ ├── main.yml │ │ │ │ │ ├── parent1.yml │ │ │ │ │ └── parent2.yml │ │ │ ├── RemoteConfig │ │ │ │ ├── Child │ │ │ │ │ ├── child.yml │ │ │ │ │ ├── expected.yml │ │ │ │ │ └── main.yml │ │ │ │ ├── Cycle │ │ │ │ │ └── .swiftlint.yml │ │ │ │ ├── LocalRef │ │ │ │ │ ├── .swiftlint.yml │ │ │ │ │ ├── child1.yml │ │ │ │ │ └── child2.yml │ │ │ │ └── Parent │ │ │ │ │ ├── expected.yml │ │ │ │ │ ├── main.yml │ │ │ │ │ └── parent.yml │ │ │ ├── custom.yml │ │ │ ├── custom_included_excluded.yml │ │ │ ├── custom_rules.yml │ │ │ └── custom_rules_only.yml │ │ ├── test.txt │ │ └── test.yml │ ├── RuleConfigurationDescriptionTests.swift │ ├── RuleConfigurationTests.swift │ ├── RuleTests.swift │ ├── RulesTests.swift │ ├── SeverityLevelsConfigurationTests.swift │ ├── SourceKitCrashTests.swift │ ├── StringExtensionTests.swift │ ├── StringViewExtensionTests.swift │ ├── SwiftLintFileTests.swift │ ├── SwiftSyntaxKindBridgeTests.swift │ ├── SwiftVersionTests.swift │ ├── YamlParserTests.swift │ └── YamlSwiftLintTests.swift ├── GeneratedTests │ ├── GeneratedTests_01.swift │ ├── GeneratedTests_02.swift │ ├── GeneratedTests_03.swift │ ├── GeneratedTests_04.swift │ ├── GeneratedTests_05.swift │ ├── GeneratedTests_06.swift │ ├── GeneratedTests_07.swift │ ├── GeneratedTests_08.swift │ ├── GeneratedTests_09.swift │ └── GeneratedTests_10.swift ├── IntegrationTests │ ├── IntegrationTests.swift │ └── default_rule_configurations.yml ├── MacroTests │ ├── AcceptableByConfigurationElementTests.swift │ ├── AutoConfigParserTests.swift │ └── SwiftSyntaxRuleTests.swift ├── TestHelpers │ ├── RuleDescription+Examples.swift │ ├── RuleMock.swift │ ├── SwiftLintTestCase.swift │ ├── TestHelpers.swift │ └── TestResources.swift ├── generated_tests.bzl └── test_macros.bzl ├── WORKSPACE ├── assets ├── custom-rule.png ├── macstadium.png ├── presentation.svg ├── realm.png └── screenshot.png ├── bazel ├── BUILD ├── CollectionConcurrencyKit.BUILD ├── CryptoSwift.BUILD ├── SWXMLHash.BUILD ├── SwiftArgumentParser.BUILD ├── SwiftyTextTable.BUILD ├── deps.bzl ├── extensions.bzl └── repos.bzl └── tools ├── BUILD ├── Version.swift.template ├── add-new-changelog-section.sh ├── create-github-release.sh ├── generate-release-notes.sh ├── get-version ├── info.json.template ├── oss-check ├── stale-issues.rb ├── test-analyze.sh └── update-artifact-bundle.sh /.bazelignore: -------------------------------------------------------------------------------- 1 | .build 2 | -------------------------------------------------------------------------------- /.bazelrc: -------------------------------------------------------------------------------- 1 | common --enable_bzlmod 2 | 3 | try-import %workspace%/ci.bazelrc 4 | try-import %workspace%/user.bazelrc 5 | 6 | build --enable_platform_specific_config 7 | build:macos --apple_crosstool_top=@local_config_apple_cc//:toolchain 8 | build:macos --crosstool_top=@local_config_apple_cc//:toolchain 9 | build:macos --host_crosstool_top=@local_config_apple_cc//:toolchain 10 | 11 | build --macos_minimum_os=13.5 --host_macos_minimum_os=13.5 12 | build --disk_cache=~/.bazel_cache 13 | build --experimental_remote_cache_compression 14 | build --remote_build_event_upload=minimal 15 | build --nolegacy_important_outputs 16 | build --incompatible_strict_action_env 17 | 18 | build:release \ 19 | --compilation_mode=opt \ 20 | --features=swift.opt_uses_wmo 21 | -------------------------------------------------------------------------------- /.bazelversion: -------------------------------------------------------------------------------- 1 | 7.6.1 2 | -------------------------------------------------------------------------------- /.bcr/config.yml: -------------------------------------------------------------------------------- 1 | fixedReleaser: 2 | login: SimplyDanny 3 | email: danny.moesch@icloud.com 4 | -------------------------------------------------------------------------------- /.bcr/metadata.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "homepage": "https://github.com/realm/SwiftLint", 3 | "maintainers": [ 4 | { 5 | "email": "jp@jpsim.com", 6 | "github": "jpsim", 7 | "name": "JP Simard" 8 | }, 9 | { 10 | "email": "danny.moesch@icloud.com", 11 | "github": "SimplyDanny", 12 | "name": "Danny Mösch" 13 | } 14 | ], 15 | "repository": [ 16 | "github:realm/SwiftLint" 17 | ], 18 | "versions": [], 19 | "yanked_versions": {} 20 | } 21 | -------------------------------------------------------------------------------- /.bcr/patches/no-warnings-as-errors.patch: -------------------------------------------------------------------------------- 1 | diff --git a/BUILD b/BUILD 2 | index e862723d1..40aba4d51 100644 3 | --- a/BUILD 4 | +++ b/BUILD 5 | @@ -23,7 +23,6 @@ config_setting( 6 | ) 7 | 8 | copts = [ 9 | - "-warnings-as-errors", 10 | "-enable-upcoming-feature", 11 | "ExistentialAny", 12 | "-enable-upcoming-feature", 13 | -------------------------------------------------------------------------------- /.bcr/presubmit.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | verify_targets_linux: 3 | name: Verify Targets (Linux) 4 | platform: ubuntu2004 5 | bazel: 7.x 6 | environment: 7 | CC: "clang" 8 | SWIFT_VERSION: "6.0.3" 9 | SWIFT_HOME: "$HOME/swift-$SWIFT_VERSION" 10 | PATH: "$PATH:$SWIFT_HOME/usr/bin" 11 | shell_commands: 12 | - "echo --- Downloading and extracting Swift $SWIFT_VERSION to $SWIFT_HOME" 13 | - "mkdir $SWIFT_HOME" 14 | - "curl https://download.swift.org/swift-${SWIFT_VERSION}-release/ubuntu2004/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE-ubuntu20.04.tar.gz | tar xvz --strip-components=1 -C $SWIFT_HOME" 15 | build_flags: 16 | - "--action_env=PATH" 17 | build_targets: 18 | - '@swiftlint//:swiftlint' 19 | verify_targets_macos: 20 | name: Verify Targets (macOS) 21 | platform: macos 22 | bazel: 7.x 23 | build_targets: 24 | - '@swiftlint//:swiftlint' 25 | build_flags: 26 | - "--repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1" 27 | -------------------------------------------------------------------------------- /.bcr/source.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://github.com/realm/SwiftLint/releases/download/{TAG}/bazel.tar.gz", 3 | "integrity": "", 4 | "strip_prefix": "", 5 | "patch_strip": 1 6 | } 7 | -------------------------------------------------------------------------------- /.buildkite/pipeline.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - label: "Bazel" 3 | commands: 4 | - echo "+++ Build" 5 | - bazel build :swiftlint 6 | - echo "+++ Test" 7 | - make bazel_test 8 | - label: "SwiftPM" 9 | commands: 10 | - echo "+++ Generate Template Rule" 11 | - swift run swiftlint-dev rules template FooBarBaz --rewriter --id foo_bar --config --kind metrics --severity error --test 12 | - echo "+++ Test" 13 | - make spm_test 14 | env: 15 | SKIP_INTEGRATION_TESTS: true 16 | - label: "Danger" 17 | commands: 18 | - echo "+++ Install Bundler" 19 | - gem install bundler -v 2.4.22 20 | - echo "+++ Run OSS Scan" 21 | - make oss_scan 22 | artifact_paths: "oss-check-summary.md" 23 | priority: 10 24 | - label: "TSan Tests" 25 | commands: 26 | - echo "+++ Test" 27 | - make bazel_test_tsan 28 | - label: "Registration" 29 | commands: 30 | - echo "+++ Register Rules and Reporters" 31 | - make --always-make bazel_register 32 | - echo "+++ Diff Files" 33 | - git diff --quiet HEAD 34 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !Plugins 3 | !Source 4 | !Tests 5 | !Package.* 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | CHANGELOG.md merge=union 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us improve. 4 | 5 | --- 6 | 7 | ### New Issue Checklist 8 | 9 | - [ ] I've Updated SwiftLint to the latest version. 10 | - [ ] I've searched for [existing GitHub issues](https://github.com/realm/SwiftLint/issues). 11 | 12 | ### Bug Description 13 | 14 | A clear and concise description of what the bug is. Ideally, provide a small (but compilable) example code snippet that 15 | can be used to reproduce the issue. 16 | 17 | ```swift 18 | // This triggers a violation: 19 | let foo = try! bar() 20 | ``` 21 | 22 | Mention the command or other SwiftLint integration method that caused the issue. Include stack traces or command output. 23 | 24 | ```bash 25 | $ swiftlint lint [--no-cache] [--fix] 26 | ``` 27 | 28 | ### Environment 29 | 30 | * SwiftLint version (run `swiftlint version` to be sure) 31 | * Xcode version (run `xcodebuild -version` to be sure) 32 | * Installation method used (Homebrew, CocoaPods, building from source, etc) 33 | * Configuration file: 34 | 35 | ```yml 36 | # insert yaml contents here 37 | ``` 38 | 39 | Are you using [nested configurations](https://github.com/realm/SwiftLint#nested-configurations)? If so, paste their 40 | relative paths and respective contents. 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/proposal.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature or Enhancement Proposal 3 | about: Let us know about a feature idea or propose an improvement. 4 | 5 | --- 6 | 7 | ### New Issue Checklist 8 | 9 | - [ ] I've Updated SwiftLint to the latest version. 10 | - [ ] I've searched for [existing GitHub issues](https://github.com/realm/SwiftLint/issues). 11 | 12 | ### Feature or Enhancement Proposal 13 | 14 | Describe you idea or proposal here. This can be a new feature, an enhancement to an existing feature, or a change to the 15 | project's behavior. Be sure to include the rationale behind the proposal and any relevant context or examples. 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/rule-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Rule Request 3 | about: Share your idea for a new rule. 4 | 5 | --- 6 | 7 | ### New Issue Checklist 8 | 9 | - [ ] Updated SwiftLint to the latest version 10 | - [ ] I searched for [existing GitHub issues](https://github.com/realm/SwiftLint/issues) 11 | 12 | ### New Rule Request 13 | 14 | Please describe the rule idea, format this issue's title as `Rule Request: [Rule Name]` and describe: 15 | 16 | 1. Why should this rule be added? Share links to existing discussion about what 17 | the community thinks about this. 18 | 2. Provide several examples of what _would_ and _wouldn't_ trigger violations. 19 | 3. Should the rule be configurable, if so what parameters should be configurable? 20 | 4. Should the rule be opt-in or enabled by default? Why? 21 | See [README.md](../README.md#opt-in-rules) for guidelines on when to mark a rule as opt-in. 22 | -------------------------------------------------------------------------------- /.github/actions/bazel-linux-build/action.yml: -------------------------------------------------------------------------------- 1 | name: Bazel Linux Build 2 | description: Common steps to build SwiftLint with Bazel on GitHub Linux runners 3 | inputs: 4 | target: 5 | description: The Bazel target to build 6 | default: //:swiftlint 7 | runs: 8 | using: composite 9 | steps: 10 | - name: Create ci.bazelrc file 11 | shell: bash 12 | run: echo "$CI_BAZELRC_FILE_CONTENT" | base64 -d > ci.bazelrc 13 | env: 14 | CI_BAZELRC_FILE_CONTENT: ${{ env.CI_BAZELRC_FILE_CONTENT }} 15 | - name: Apply patch 16 | shell: bash 17 | run: git apply --ignore-whitespace .bcr/patches/no-warnings-as-errors.patch 18 | - name: Build SwiftLint with Bazel 19 | shell: bash 20 | run: | 21 | export PATH="/usr/share/swift/usr/bin:$PATH" 22 | bazel build --config release ${{ inputs.target }} 23 | env: 24 | CC: clang 25 | -------------------------------------------------------------------------------- /.github/actions/run-make/action.yml: -------------------------------------------------------------------------------- 1 | name: Run Make Rule 2 | description: Runs a specified Makefile rule 3 | inputs: 4 | rule: 5 | description: The Makefile rule to run 6 | required: true 7 | default: build 8 | runs: 9 | using: composite 10 | steps: 11 | - run: | 12 | awk ' 13 | $0 ~ "${{ inputs.rule }}:" { in_rule = 1; next } 14 | in_rule && /^\t/ { print $0 } 15 | in_rule && !/^\t/ { in_rule = 0 } 16 | ' Makefile | while IFS= read -r command; do 17 | eval "$command" 18 | done 19 | shell: bash 20 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Keep GitHub Actions up to date with GitHub's Dependabot... 2 | # https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot 3 | # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem 4 | version: 2 5 | updates: 6 | - package-ecosystem: github-actions 7 | directory: / 8 | groups: 9 | github-actions: 10 | patterns: 11 | - "*" # Group all Actions updates into a single larger pull request 12 | schedule: 13 | interval: weekly 14 | -------------------------------------------------------------------------------- /.github/plugins-sync.yml: -------------------------------------------------------------------------------- 1 | SimplyDanny/SwiftLintPlugins: 2 | - Plugins/ 3 | -------------------------------------------------------------------------------- /.github/workflows/actor-credentials.yml: -------------------------------------------------------------------------------- 1 | name: Actor Credentials 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | actor: 7 | required: true 8 | type: string 9 | description: 'GitHub actor to use for configuration and authoring' 10 | outputs: 11 | author_name: 12 | description: "The Git author name" 13 | value: ${{ jobs.configure.outputs.name }} 14 | author_email: 15 | description: "The Git author email" 16 | value: ${{ jobs.configure.outputs.email }} 17 | author_uppercase: 18 | description: "The author name in uppercase" 19 | value: ${{ jobs.configure.outputs.uppercase_name }} 20 | 21 | jobs: 22 | configure: 23 | runs-on: ubuntu-24.04 24 | outputs: 25 | name: ${{ steps.configure_git_author.outputs.name }} 26 | email: ${{ steps.configure_git_author.outputs.email }} 27 | uppercase_name: ${{ steps.retrieve_author.outputs.name }} 28 | permissions: 29 | contents: write 30 | steps: 31 | - name: Retrieve author in uppercase 32 | id: retrieve_author 33 | run: | 34 | AUTHOR=$(echo ${{ inputs.actor }} | tr '[:lower:]' '[:upper:]') 35 | echo "name=${AUTHOR}" >> "$GITHUB_OUTPUT" 36 | - name: Configure Git author 37 | id: configure_git_author 38 | uses: Homebrew/actions/git-user-config@master 39 | with: 40 | token: ${{ secrets[format('PERSONAL_GITHUB_TOKEN_{0}', steps.retrieve_author.outputs.name)] }} 41 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | bazel_linux: 13 | name: Bazel, Linux, Swift 6.1 # pre-installed 14 | runs-on: ubuntu-24.04 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: ./.github/actions/bazel-linux-build 18 | name: Build SwiftLint with Bazel 19 | env: 20 | CI_BAZELRC_FILE_CONTENT: ${{ secrets.CI_BAZELRC_FILE_CONTENT }} 21 | 22 | plugins_linux: 23 | name: SPM plugins, Linux, Swift ${{ matrix.version }} 24 | runs-on: ubuntu-24.04 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | include: 29 | - image: swift:5.9-focal 30 | version: '5.9' 31 | - image: swift:5.10-noble 32 | version: '5.10' 33 | - image: swift:6.0-noble 34 | version: '6.0' 35 | - image: swift:6.1-noble 36 | version: '6.1' 37 | container: ${{ matrix.image }} 38 | steps: 39 | - uses: actions/checkout@v4 40 | - name: Build plugins 41 | uses: ./.github/actions/run-make 42 | with: 43 | rule: spm_build_plugins 44 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | pull_request: 5 | 6 | permissions: 7 | contents: read 8 | pull-requests: write 9 | 10 | jobs: 11 | lint-swift: 12 | name: Swift 13 | runs-on: ubuntu-24.04 # "Noble Numbat" 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: ./.github/actions/bazel-linux-build 17 | name: Build SwiftLint with Bazel 18 | env: 19 | CI_BAZELRC_FILE_CONTENT: ${{ secrets.CI_BAZELRC_FILE_CONTENT }} 20 | - name: Lint 21 | run: ./bazel-bin/swiftlint lint --reporter github-actions-logging --strict 2> /dev/null 22 | lint-markdown: 23 | name: Markdown 24 | runs-on: ubuntu-24.04 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Lint 28 | uses: DavidAnson/markdownlint-cli2-action@v20 29 | with: 30 | globs: | 31 | CHANGELOG.md 32 | CONTRIBUTING.md 33 | README.md 34 | lint-actions: 35 | name: Actions 36 | runs-on: ubuntu-24.04 37 | steps: 38 | - uses: actions/checkout@v4 39 | - name: Register problem matcher 40 | run: | 41 | curl -sSL https://raw.githubusercontent.com/rhysd/actionlint/main/.github/actionlint-matcher.json > actionlint-matcher.json 42 | echo "::add-matcher::actionlint-matcher.json" 43 | - name: Lint 44 | uses: docker://rhysd/actionlint:latest 45 | with: 46 | args: -color 47 | -------------------------------------------------------------------------------- /.github/workflows/plugins-sync.yml: -------------------------------------------------------------------------------- 1 | name: Plugins Sync 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - 'Plugins/**' 9 | workflow_dispatch: 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | sync: 16 | name: Sync Plugins Folder 17 | runs-on: ubuntu-24.04 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v4 21 | - name: Run file sync 22 | uses: BetaHuhn/repo-file-sync-action@v1 23 | with: 24 | GH_PAT: ${{ secrets.SIMPLYDANNY_PLUGINS_SYNC }} 25 | IS_FINE_GRAINED: true 26 | CONFIG_PATH: .github/plugins-sync.yml 27 | SKIP_PR: true 28 | COMMIT_PREFIX: 🔄 Workflow in 'realm/SwiftLint' 29 | -------------------------------------------------------------------------------- /.github/workflows/stale-issues.yml: -------------------------------------------------------------------------------- 1 | name: Stale Issues 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 15 * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | 11 | jobs: 12 | close-stale-issues: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v4 17 | - name: Mark or close stale issues 18 | run: | 19 | ./tools/stale-issues.rb ${{ github.repository }} 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | 8 | permissions: 9 | contents: read 10 | 11 | env: 12 | SKIP_INTEGRATION_TESTS: 'true' 13 | 14 | jobs: 15 | spm_linux: 16 | name: SPM, Linux, Swift 6.1 17 | runs-on: ubuntu-24.04 18 | container: swift:6.1-noble 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: actions/cache@v4 22 | with: 23 | key: ${{ runner.os }}-swift-spm-${{ hashFiles('Package.resolved') }} 24 | restore-keys: ${{ runner.os }}-swift-spm- 25 | path: .build 26 | - name: Run tests 27 | uses: ./.github/actions/run-make 28 | with: 29 | rule: spm_test 30 | 31 | spm_macos: 32 | name: SPM, macOS ${{ matrix.macOS }}, Xcode ${{ matrix.xcode }} 33 | runs-on: macos-${{ matrix.macOS }} 34 | strategy: 35 | matrix: 36 | include: 37 | - macOS: '14' 38 | xcode: '15.4' 39 | - macOS: '15' 40 | xcode: '16.4' 41 | env: 42 | DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app 43 | steps: 44 | - uses: actions/checkout@v4 45 | - uses: actions/cache@v4 46 | with: 47 | key: ${{ runner.os }}-xcode-spm-${{ matrix.xcode }}-${{ hashFiles('Package.resolved') }} 48 | restore-keys: ${{ runner.os }}-xcode-spm-${{ matrix.xcode }}- 49 | path: .build 50 | - name: Run tests 51 | run: make spm_test 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | 4 | ## Build generated 5 | build/ 6 | DerivedData 7 | 8 | ## Various settings 9 | *.pbxuser 10 | !default.pbxuser 11 | *.mode1v3 12 | !default.mode1v3 13 | *.mode2v3 14 | !default.mode2v3 15 | *.perspectivev3 16 | !default.perspectivev3 17 | xcuserdata 18 | 19 | ## Other 20 | *.xccheckout 21 | *.moved-aside 22 | *.xcuserstate 23 | *.xcscmblueprint 24 | default.profraw 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | #Pods/ 37 | 38 | # SwiftLint 39 | 40 | SwiftLint.xcodeproj 41 | SwiftLint.pkg 42 | *.zip 43 | benchmark_* 44 | docs/ 45 | rule_docs/ 46 | bazel.tar.gz 47 | bazel.tar.gz.sha256 48 | ci.bazelrc 49 | user.bazelrc 50 | 51 | # Swift Package Manager 52 | # 53 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 54 | Packages/ 55 | .build/ 56 | .swiftpm/ 57 | 58 | # macOS 59 | .DS_Store 60 | 61 | # Bundler 62 | .bundle/ 63 | bundle/ 64 | bin/ 65 | 66 | # Bazel 67 | /bazel-* 68 | /MODULE.bazel.lock 69 | 70 | # Danger 71 | osscheck/ 72 | oss-check-summary.md 73 | -------------------------------------------------------------------------------- /.jazzy.yaml: -------------------------------------------------------------------------------- 1 | module: SwiftLintCore 2 | author: JP Simard, SwiftLint Contributors 3 | author_url: https://jpsim.com 4 | root_url: https://realm.github.io/SwiftLint/ 5 | github_url: https://github.com/realm/SwiftLint 6 | github_file_prefix: https://github.com/realm/SwiftLint/tree/main 7 | swift_build_tool: spm 8 | theme: fullwidth 9 | clean: true 10 | copyright: '© 2023 [JP Simard](https://jpsim.com) under MIT.' 11 | 12 | documentation: rule_docs/*.md 13 | hide_unlisted_documentation: true 14 | custom_categories_unlisted_prefix: '' 15 | exclude: 16 | # TODO: Document extensions 17 | - Source/SwiftLintCore/Extensions/*.swift 18 | custom_categories: 19 | - name: Rules 20 | children: 21 | - Rule Directory 22 | -------------------------------------------------------------------------------- /.markdownlint.yml: -------------------------------------------------------------------------------- 1 | MD013: 2 | line_length: 120 3 | code_blocks: false 4 | MD024: 5 | siblings_only: true 6 | MD033: 7 | allowed_elements: 8 | - details 9 | - summary 10 | -------------------------------------------------------------------------------- /.pre-commit-hooks.yaml: -------------------------------------------------------------------------------- 1 | - id: swiftlint 2 | name: SwiftLint 3 | description: "Check Swift files for issues with SwiftLint" 4 | entry: "swiftlint --quiet" 5 | language: swift 6 | types: [swift] 7 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.4.2 2 | -------------------------------------------------------------------------------- /.spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | external_links: 3 | documentation: "https://realm.github.io/SwiftLint" 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'cocoapods' 4 | gem 'danger' 5 | gem 'base64' 6 | gem 'jazzy', '~> 0.15.3' 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2025 The SwiftLint Contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Plugins/SwiftLintBuildToolPlugin/Path+Helpers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PackagePlugin 3 | 4 | extension Path { 5 | var directoryContainsConfigFile: Bool { 6 | FileManager.default.fileExists(atPath: "\(self)/.swiftlint.yml") 7 | } 8 | 9 | var depth: Int { 10 | URL(fileURLWithPath: "\(self)").pathComponents.count 11 | } 12 | 13 | func isDescendant(of path: Path) -> Bool { 14 | "\(self)".hasPrefix("\(path)") 15 | } 16 | 17 | func resolveWorkingDirectory(in directory: Path) throws -> Path { 18 | guard "\(self)".hasPrefix("\(directory)") else { 19 | throw SwiftLintBuildToolPluginError.pathNotInDirectory(path: self, directory: directory) 20 | } 21 | 22 | let path: Path? = sequence(first: self) { path in 23 | let path: Path = path.removingLastComponent() 24 | guard "\(path)".hasPrefix("\(directory)") else { 25 | return nil 26 | } 27 | return path 28 | } 29 | .reversed() 30 | .first(where: \.directoryContainsConfigFile) 31 | 32 | return path ?? directory 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPluginError.swift: -------------------------------------------------------------------------------- 1 | import PackagePlugin 2 | 3 | enum SwiftLintBuildToolPluginError: Error, CustomStringConvertible { 4 | case pathNotInDirectory(path: Path, directory: Path) 5 | case swiftFilesNotInProjectDirectory(Path) 6 | case swiftFilesNotInWorkingDirectory(Path) 7 | 8 | var description: String { 9 | switch self { 10 | case let .pathNotInDirectory(path, directory): 11 | "Path '\(path)' is not in directory '\(directory)'." 12 | case let .swiftFilesNotInProjectDirectory(directory): 13 | "Swift files are not in project directory '\(directory)'." 14 | case let .swiftFilesNotInWorkingDirectory(directory): 15 | "Swift files are not in working directory '\(directory)'." 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Rules.md: -------------------------------------------------------------------------------- 1 | Rule documentation has moved [here](https://realm.github.io/SwiftLint/rule-directory.html). 2 | -------------------------------------------------------------------------------- /Source/DyldWarningWorkaround/DyldWarningWorkaround.c: -------------------------------------------------------------------------------- 1 | #ifdef __APPLE__ 2 | 3 | #include "objc_dupclass.h" 4 | 5 | OBJC_DUPCLASS(_TtC11SwiftSyntax11SyntaxArena); 6 | OBJC_DUPCLASS(_TtC11SwiftSyntax13SyntaxVisitor); 7 | OBJC_DUPCLASS(_TtC11SwiftSyntax14SyntaxRewriter); 8 | OBJC_DUPCLASS(_TtC11SwiftSyntax16BumpPtrAllocator); 9 | OBJC_DUPCLASS(_TtC11SwiftSyntax16SyntaxAnyVisitor); 10 | OBJC_DUPCLASS(_TtC11SwiftSyntax18ParsingSyntaxArena); 11 | OBJC_DUPCLASS(_TtC11SwiftSyntax23SourceLocationConverter); 12 | OBJC_DUPCLASS(_TtC11SwiftSyntax26IncrementalParseTransition); 13 | OBJC_DUPCLASS(_TtC11SwiftSyntax35IncrementalParseReusedNodeCollector); 14 | OBJC_DUPCLASS(_TtC11SwiftParserP33_78149DB072C20084E7D780D86E26C3AF41StringLiteralExpressionIndentationChecker); 15 | 16 | #endif // __APPLE__ 17 | -------------------------------------------------------------------------------- /Source/DyldWarningWorkaround/include/objc_dupclass.h: -------------------------------------------------------------------------------- 1 | // https://github.com/keith/objc_dupclass 2 | #include <stdint.h> 3 | 4 | // TODO: This isn't entirely accurate, but I'm not sure how to more accurately determine 5 | #if (defined(__arm64__) || defined(DUPCLASS_FORCE_DATA_CONST)) && !defined(DUPCLASS_FORCE_DATA) 6 | #define SECTION "__DATA_CONST" 7 | #else 8 | #define SECTION "__DATA" 9 | #endif 10 | 11 | // Struct layout from https://github.com/apple-oss-distributions/objc4/blob/8701d5672d3fd3cd817aeb84db1077aafe1a1604/runtime/objc-abi.h#L175-L183 12 | #define OBJC_DUPCLASS(kclass) \ 13 | __attribute__((used)) __attribute__((visibility("hidden"))) \ 14 | static struct { uint32_t version; uint32_t flags; const char name[128]; } \ 15 | const __duplicate_class_##kclass = { 0, 0, #kclass }; \ 16 | \ 17 | __attribute__((used)) __attribute__((visibility("hidden"))) \ 18 | __attribute__((section (SECTION",__objc_dupclass"))) \ 19 | const void* __set___objc_dupclass_sym___duplicate_class_##kclass = &__duplicate_class_##kclass 20 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Exports.swift: -------------------------------------------------------------------------------- 1 | @_exported import SwiftLintCore 2 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Models/ImportUsage.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Represents unused or missing import statements. 4 | enum ImportUsage { 5 | /// The import is unused. Range is for the entire import statement. 6 | case unused(module: String, range: NSRange) 7 | /// The file is missing an explicit import of the `module`. 8 | case missing(module: String) 9 | 10 | /// The range where the violation for this import usage should be reported. 11 | var violationRange: NSRange? { 12 | switch self { 13 | case .unused(_, let range): 14 | return range 15 | case .missing: 16 | return nil 17 | } 18 | } 19 | 20 | /// The reason why this import usage is a violation. 21 | var violationReason: String? { 22 | switch self { 23 | case .unused: 24 | return nil 25 | case .missing(let module): 26 | return "Missing import for referenced module '\(module)'" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/Idiomatic/FallthroughRule.swift: -------------------------------------------------------------------------------- 1 | import SwiftSyntax 2 | 3 | @SwiftSyntaxRule(optIn: true) 4 | struct FallthroughRule: Rule { 5 | var configuration = SeverityConfiguration<Self>(.warning) 6 | 7 | static let description = RuleDescription( 8 | identifier: "fallthrough", 9 | name: "Fallthrough", 10 | description: "Fallthrough should be avoided", 11 | kind: .idiomatic, 12 | nonTriggeringExamples: [ 13 | Example(""" 14 | switch foo { 15 | case .bar, .bar2, .bar3: 16 | something() 17 | } 18 | """), 19 | ], 20 | triggeringExamples: [ 21 | Example(""" 22 | switch foo { 23 | case .bar: 24 | ↓fallthrough 25 | case .bar2: 26 | something() 27 | } 28 | """), 29 | ] 30 | ) 31 | } 32 | 33 | private extension FallthroughRule { 34 | final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> { 35 | override func visitPost(_ node: FallThroughStmtSyntax) { 36 | violations.append(node.positionAfterSkippingLeadingTrivia) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameNoSpaceRule.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceKittenFramework 3 | 4 | struct FileNameNoSpaceRule: OptInRule, SourceKitFreeRule { 5 | var configuration = FileNameNoSpaceConfiguration() 6 | 7 | static let description = RuleDescription( 8 | identifier: "file_name_no_space", 9 | name: "File Name no Space", 10 | description: "File name should not contain any whitespace", 11 | kind: .idiomatic 12 | ) 13 | 14 | func validate(file: SwiftLintFile) -> [StyleViolation] { 15 | guard let filePath = file.path, 16 | case let fileName = filePath.bridge().lastPathComponent, 17 | !configuration.excluded.contains(fileName), 18 | fileName.rangeOfCharacter(from: .whitespaces) != nil else { 19 | return [] 20 | } 21 | 22 | return [ 23 | StyleViolation( 24 | ruleDescription: Self.description, 25 | severity: configuration.severity, 26 | location: Location(file: filePath, line: 1) 27 | ), 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceCastRule.swift: -------------------------------------------------------------------------------- 1 | import SwiftSyntax 2 | 3 | @SwiftSyntaxRule 4 | struct ForceCastRule: Rule { 5 | var configuration = SeverityConfiguration<Self>(.error) 6 | 7 | static let description = RuleDescription( 8 | identifier: "force_cast", 9 | name: "Force Cast", 10 | description: "Force casts should be avoided", 11 | kind: .idiomatic, 12 | nonTriggeringExamples: [ 13 | Example("NSNumber() as? Int") 14 | ], 15 | triggeringExamples: [ Example("NSNumber() ↓as! Int") ] 16 | ) 17 | } 18 | 19 | private extension ForceCastRule { 20 | final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> { 21 | override func visitPost(_ node: AsExprSyntax) { 22 | if node.questionOrExclamationMark?.tokenKind == .exclamationMark { 23 | violations.append(node.asKeyword.positionAfterSkippingLeadingTrivia) 24 | } 25 | } 26 | 27 | override func visitPost(_ node: UnresolvedAsExprSyntax) { 28 | if node.questionOrExclamationMark?.tokenKind == .exclamationMark { 29 | violations.append(node.asKeyword.positionAfterSkippingLeadingTrivia) 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceTryRule.swift: -------------------------------------------------------------------------------- 1 | import SwiftSyntax 2 | 3 | @SwiftSyntaxRule 4 | struct ForceTryRule: Rule { 5 | var configuration = SeverityConfiguration<Self>(.error) 6 | 7 | static let description = RuleDescription( 8 | identifier: "force_try", 9 | name: "Force Try", 10 | description: "Force tries should be avoided", 11 | kind: .idiomatic, 12 | nonTriggeringExamples: [ 13 | Example(""" 14 | func a() throws {} 15 | do { 16 | try a() 17 | } catch {} 18 | """), 19 | ], 20 | triggeringExamples: [ 21 | Example(""" 22 | func a() throws {} 23 | ↓try! a() 24 | """), 25 | ] 26 | ) 27 | } 28 | 29 | private extension ForceTryRule { 30 | final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> { 31 | override func visitPost(_ node: TryExprSyntax) { 32 | if node.questionOrExclamationMark?.tokenKind == .exclamationMark { 33 | violations.append(node.positionAfterSkippingLeadingTrivia) 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferNimbleRule.swift: -------------------------------------------------------------------------------- 1 | import SwiftSyntax 2 | 3 | @SwiftSyntaxRule(optIn: true) 4 | struct PreferNimbleRule: Rule { 5 | var configuration = SeverityConfiguration<Self>(.warning) 6 | 7 | static let description = RuleDescription( 8 | identifier: "prefer_nimble", 9 | name: "Prefer Nimble", 10 | description: "Prefer Nimble matchers over XCTAssert functions", 11 | kind: .idiomatic, 12 | nonTriggeringExamples: [ 13 | Example("expect(foo) == 1"), 14 | Example("expect(foo).to(equal(1))"), 15 | ], 16 | triggeringExamples: [ 17 | Example("↓XCTAssertTrue(foo)"), 18 | Example("↓XCTAssertEqual(foo, 2)"), 19 | Example("↓XCTAssertNotEqual(foo, 2)"), 20 | Example("↓XCTAssertNil(foo)"), 21 | Example("↓XCTAssert(foo)"), 22 | Example("↓XCTAssertGreaterThan(foo, 10)"), 23 | ] 24 | ) 25 | } 26 | 27 | private extension PreferNimbleRule { 28 | final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> { 29 | override func visitPost(_ node: FunctionCallExprSyntax) { 30 | if let expr = node.calledExpression.as(DeclReferenceExprSyntax.self), 31 | expr.baseName.text.starts(with: "XCTAssert") { 32 | violations.append(node.positionAfterSkippingLeadingTrivia) 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/Lint/IBInspectableInExtensionRule.swift: -------------------------------------------------------------------------------- 1 | import SwiftSyntax 2 | 3 | @SwiftSyntaxRule(optIn: true) 4 | struct IBInspectableInExtensionRule: Rule { 5 | var configuration = SeverityConfiguration<Self>(.warning) 6 | 7 | static let description = RuleDescription( 8 | identifier: "ibinspectable_in_extension", 9 | name: "IBInspectable in Extension", 10 | description: "Extensions shouldn't add @IBInspectable properties", 11 | kind: .lint, 12 | nonTriggeringExamples: [ 13 | Example(""" 14 | class Foo { 15 | @IBInspectable private var x: Int 16 | } 17 | """), 18 | ], 19 | triggeringExamples: [ 20 | Example(""" 21 | extension Foo { 22 | ↓@IBInspectable private var x: Int 23 | } 24 | """), 25 | ] 26 | ) 27 | } 28 | 29 | private extension IBInspectableInExtensionRule { 30 | final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> { 31 | override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { 32 | .allExcept(ExtensionDeclSyntax.self, VariableDeclSyntax.self) 33 | } 34 | 35 | override func visitPost(_ node: AttributeSyntax) { 36 | if node.attributeNameText == "IBInspectable" { 37 | violations.append(node.positionAfterSkippingLeadingTrivia) 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/Lint/NotificationCenterDetachmentRuleExamples.swift: -------------------------------------------------------------------------------- 1 | internal struct NotificationCenterDetachmentRuleExamples { 2 | static let nonTriggeringExamples = [ 3 | Example(""" 4 | class Foo { 5 | deinit { 6 | NotificationCenter.default.removeObserver(self) 7 | } 8 | } 9 | """), 10 | Example(""" 11 | class Foo { 12 | func bar() { 13 | NotificationCenter.default.removeObserver(otherObject) 14 | } 15 | } 16 | """), 17 | ] 18 | 19 | static let triggeringExamples = [ 20 | Example(""" 21 | class Foo { 22 | func bar() { 23 | ↓NotificationCenter.default.removeObserver(self) 24 | } 25 | } 26 | """), 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRule.swift: -------------------------------------------------------------------------------- 1 | import SwiftSyntax 2 | 3 | @SwiftSyntaxRule(optIn: true) 4 | struct ClosureBodyLengthRule: Rule { 5 | private static let defaultWarningThreshold = 30 6 | 7 | var configuration = SeverityLevelsConfiguration<Self>(warning: Self.defaultWarningThreshold, error: 100) 8 | 9 | static let description = RuleDescription( 10 | identifier: "closure_body_length", 11 | name: "Closure Body Length", 12 | description: "Closure bodies should not span too many lines", 13 | rationale: """ 14 | "Closure bodies should not span too many lines" says it all. 15 | 16 | Possibly you could refactor your closure code and extract some of it into a function. 17 | """, 18 | kind: .metrics, 19 | nonTriggeringExamples: ClosureBodyLengthRuleExamples.nonTriggeringExamples, 20 | triggeringExamples: ClosureBodyLengthRuleExamples.triggeringExamples 21 | ) 22 | } 23 | 24 | private extension ClosureBodyLengthRule { 25 | final class Visitor: BodyLengthVisitor<ConfigurationType> { 26 | override func visitPost(_ node: ClosureExprSyntax) { 27 | registerViolations( 28 | leftBrace: node.leftBrace, 29 | rightBrace: node.rightBrace, 30 | violationNode: node.leftBrace, 31 | objectName: "Closure" 32 | ) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/AttributesConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct AttributesConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = AttributesRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "attributes_with_arguments_always_on_line_above") 10 | private(set) var attributesWithArgumentsAlwaysOnNewLine = true 11 | @ConfigurationElement(key: "always_on_same_line") 12 | private(set) var alwaysOnSameLine = Set<String>(["@IBAction", "@NSManaged"]) 13 | @ConfigurationElement(key: "always_on_line_above") 14 | private(set) var alwaysOnNewLine = Set<String>() 15 | } 16 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/BlanketDisableCommandConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct BlanketDisableCommandConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = BlanketDisableCommandRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "allowed_rules") 10 | private(set) var allowedRuleIdentifiers: Set<String> = [ 11 | "file_header", 12 | "file_length", 13 | "file_name", 14 | "file_name_no_space", 15 | "single_test_class", 16 | ] 17 | @ConfigurationElement(key: "always_blanket_disable") 18 | private(set) var alwaysBlanketDisableRuleIdentifiers: Set<String> = [] 19 | } 20 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CollectionAlignmentConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct CollectionAlignmentConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = CollectionAlignmentRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "align_colons") 10 | private(set) var alignColons = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ColonConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct ColonConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = ColonRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "flexible_right_spacing") 10 | private(set) var flexibleRightSpacing = false 11 | @ConfigurationElement(key: "apply_to_dictionaries") 12 | private(set) var applyToDictionaries = true 13 | } 14 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ComputedAccessorsOrderConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct ComputedAccessorsOrderConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = ComputedAccessorsOrderRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum Order: String { 9 | case getSet = "get_set" 10 | case setGet = "set_get" 11 | } 12 | 13 | @ConfigurationElement(key: "severity") 14 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 15 | @ConfigurationElement(key: "order") 16 | private(set) var order = Order.getSet 17 | } 18 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ConditionalReturnsOnNewlineConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct ConditionalReturnsOnNewlineConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = ConditionalReturnsOnNewlineRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "if_only") 10 | private(set) var ifOnly = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | import SwiftLintCore 3 | 4 | @AutoConfigParser 5 | struct CyclomaticComplexityConfiguration: RuleConfiguration { 6 | typealias Parent = CyclomaticComplexityRule 7 | 8 | @ConfigurationElement(inline: true) 9 | private(set) var length = SeverityLevelsConfiguration<Parent>(warning: 10, error: 20) 10 | @ConfigurationElement(key: "ignores_case_statements") 11 | private(set) var ignoresCaseStatements = false 12 | 13 | var params: [RuleParameter<Int>] { 14 | length.params 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DiscouragedDirectInitConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct DiscouragedDirectInitConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = DiscouragedDirectInitRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | 10 | @ConfigurationElement( 11 | key: "types", 12 | postprocessor: { $0.formUnion($0.map { name in "\(name).init" }) } 13 | ) 14 | private(set) var discouragedInits: Set = [ 15 | "Bundle", 16 | "NSError", 17 | "UIDevice", 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/EmptyCountConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct EmptyCountConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = EmptyCountRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.error) 9 | @ConfigurationElement(key: "only_after_dot") 10 | private(set) var onlyAfterDot = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitInitConfiguration.swift: -------------------------------------------------------------------------------- 1 | @AutoConfigParser 2 | struct ExplicitInitConfiguration: SeverityBasedRuleConfiguration { 3 | typealias Parent = ExplicitInitRule 4 | 5 | @ConfigurationElement(key: "severity") 6 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 7 | @ConfigurationElement(key: "include_bare_init") 8 | private(set) var includeBareInit = false 9 | } 10 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitTypeInterfaceConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct ExplicitTypeInterfaceConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = ExplicitTypeInterfaceRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum VariableKind: String, CaseIterable { 9 | case instance 10 | case local 11 | case `static` 12 | case `class` 13 | 14 | static let all = Set(allCases) 15 | } 16 | 17 | @ConfigurationElement(key: "severity") 18 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 19 | @ConfigurationElement(key: "excluded") 20 | private(set) var excluded = [VariableKind]() 21 | @ConfigurationElement(key: "allow_redundancy") 22 | private(set) var allowRedundancy = false 23 | 24 | var allowedKinds: Set<VariableKind> { 25 | VariableKind.all.subtracting(excluded) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileLengthConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct FileLengthConfiguration: RuleConfiguration { 5 | typealias Parent = FileLengthRule 6 | 7 | @ConfigurationElement(inline: true) 8 | private(set) var severityConfiguration = SeverityLevelsConfiguration<Parent>(warning: 400, error: 1000) 9 | @ConfigurationElement(key: "ignore_comment_only_lines") 10 | private(set) var ignoreCommentOnlyLines = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct FileNameConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = FileNameRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "excluded") 10 | private(set) var excluded = Set(["main.swift", "LinuxMain.swift"]) 11 | @ConfigurationElement(key: "excluded_paths") 12 | private(set) var excludedPaths = Set<RegularExpression>() 13 | @ConfigurationElement(key: "prefix_pattern") 14 | private(set) var prefixPattern = "" 15 | @ConfigurationElement(key: "suffix_pattern") 16 | private(set) var suffixPattern = "\\+.*" 17 | @ConfigurationElement(key: "nested_type_separator") 18 | private(set) var nestedTypeSeparator = "." 19 | @ConfigurationElement(key: "require_fully_qualified_names") 20 | private(set) var requireFullyQualifiedNames = false 21 | } 22 | 23 | extension FileNameConfiguration { 24 | func shouldExclude(filePath: String) -> Bool { 25 | let fileName = filePath.bridge().lastPathComponent 26 | if excluded.contains(fileName) { 27 | return true 28 | } 29 | return excludedPaths.contains { 30 | $0.regex.firstMatch(in: filePath, range: filePath.fullNSRange) != nil 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameNoSpaceConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct FileNameNoSpaceConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = FileNameNoSpaceRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>.warning 9 | @ConfigurationElement(key: "excluded") 10 | private(set) var excluded = Set<String>() 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileTypesOrderConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct FileTypesOrderConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = FileTypesOrderRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum FileType: String { 9 | case supportingType = "supporting_type" 10 | case mainType = "main_type" 11 | case `extension` = "extension" 12 | case previewProvider = "preview_provider" 13 | case libraryContentProvider = "library_content_provider" 14 | } 15 | 16 | @ConfigurationElement(key: "severity") 17 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 18 | @ConfigurationElement(key: "order") 19 | private(set) var order: [[FileType]] = [ 20 | [.supportingType], 21 | [.mainType], 22 | [.extension], 23 | [.previewProvider], 24 | [.libraryContentProvider], 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ForWhereConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct ForWhereConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = ForWhereRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "allow_for_as_filter") 10 | private(set) var allowForAsFilter = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionDefaultParameterAtEndConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct FunctionDefaultParameterAtEndConfiguration: SeverityBasedRuleConfiguration { 5 | // swiftlint:disable:previous type_name 6 | 7 | typealias Parent = FunctionDefaultParameterAtEndRule 8 | 9 | @ConfigurationElement(key: "severity") 10 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 11 | @ConfigurationElement(key: "ignore_first_isolation_inheritance_parameter") 12 | private(set) var ignoreFirstIsolationInheritanceParameter = true 13 | } 14 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionParameterCountConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct FunctionParameterCountConfiguration: RuleConfiguration { 5 | typealias Parent = FunctionParameterCountRule 6 | 7 | @ConfigurationElement(inline: true) 8 | private(set) var severityConfiguration = SeverityLevelsConfiguration<Parent>(warning: 5, error: 8) 9 | @ConfigurationElement(key: "ignores_default_parameters") 10 | private(set) var ignoresDefaultParameters = true 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IdentifierNameConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct IdentifierNameConfiguration: RuleConfiguration { 5 | typealias Parent = IdentifierNameRule 6 | 7 | private static let defaultOperators = ["/", "=", "-", "+", "!", "*", "|", "^", "~", "?", ".", "%", "<", ">", "&"] 8 | 9 | @ConfigurationElement(inline: true) 10 | private(set) var nameConfiguration = NameConfiguration<Parent>(minLengthWarning: 3, 11 | minLengthError: 2, 12 | maxLengthWarning: 40, 13 | maxLengthError: 60, 14 | excluded: ["id"]) 15 | 16 | @ConfigurationElement(key: "additional_operators", postprocessor: { $0.formUnion(Self.defaultOperators) }) 17 | private(set) var additionalOperators = Set<String>() 18 | } 19 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitReturnConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct ImplicitReturnConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = ImplicitReturnRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum ReturnKind: String, CaseIterable, Comparable { 9 | case closure 10 | case function 11 | case getter 12 | case `subscript` 13 | case initializer 14 | 15 | static func < (lhs: Self, rhs: Self) -> Bool { 16 | lhs.rawValue < rhs.rawValue 17 | } 18 | } 19 | 20 | static let defaultIncludedKinds = Set(ReturnKind.allCases) 21 | 22 | @ConfigurationElement(key: "severity") 23 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 24 | @ConfigurationElement(key: "included") 25 | private(set) var includedKinds = Self.defaultIncludedKinds 26 | 27 | init(includedKinds: Set<ReturnKind> = Self.defaultIncludedKinds) { 28 | self.includedKinds = includedKinds 29 | } 30 | 31 | func isKindIncluded(_ kind: ReturnKind) -> Bool { 32 | includedKinds.contains(kind) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitlyUnwrappedOptionalConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct ImplicitlyUnwrappedOptionalConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = ImplicitlyUnwrappedOptionalRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum ImplicitlyUnwrappedOptionalModeConfiguration: String { // swiftlint:disable:this type_name 9 | case all = "all" 10 | case allExceptIBOutlets = "all_except_iboutlets" 11 | case weakExceptIBOutlets = "weak_except_iboutlets" 12 | } 13 | 14 | @ConfigurationElement(key: "severity") 15 | private(set) var severityConfiguration = SeverityConfiguration<Parent>.warning 16 | @ConfigurationElement(key: "mode") 17 | private(set) var mode = ImplicitlyUnwrappedOptionalModeConfiguration.allExceptIBOutlets 18 | } 19 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/InclusiveLanguageConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct InclusiveLanguageConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = InclusiveLanguageRule 6 | 7 | private static let defaultTerms: Set<String> = [ 8 | "whitelist", 9 | "blacklist", 10 | "master", 11 | "slave", 12 | ] 13 | 14 | private static let defaultAllowedTerms: Set<String> = [ 15 | "mastercard" 16 | ] 17 | 18 | @ConfigurationElement(key: "severity") 19 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 20 | @ConfigurationElement(key: "additional_terms") 21 | private(set) var additionalTerms: Set<String>? 22 | @ConfigurationElement(key: "override_terms") 23 | private(set) var overrideTerms: Set<String>? 24 | @ConfigurationElement(key: "override_allowed_terms") 25 | private(set) var overrideAllowedTerms: Set<String>? 26 | 27 | var allTerms: [String] { 28 | let allTerms = overrideTerms ?? Self.defaultTerms 29 | return allTerms.union(additionalTerms ?? []) 30 | .map { $0.lowercased() } 31 | .unique 32 | .sorted() 33 | } 34 | 35 | var allAllowedTerms: Set<String> { 36 | Set((overrideAllowedTerms ?? Self.defaultAllowedTerms).map { $0.lowercased() }) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IndentationWidthConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct IndentationWidthConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = IndentationWidthRule 6 | 7 | private static let defaultIndentationWidth = 4 8 | 9 | @ConfigurationElement(key: "severity") 10 | private(set) var severityConfiguration = SeverityConfiguration<Parent>.warning 11 | @ConfigurationElement( 12 | key: "indentation_width", 13 | postprocessor: { 14 | if $0 < 1 { 15 | Issue.invalidConfiguration(ruleID: Parent.identifier).print() 16 | $0 = Self.defaultIndentationWidth 17 | } 18 | } 19 | ) 20 | private(set) var indentationWidth = 4 21 | @ConfigurationElement(key: "include_comments") 22 | private(set) var includeComments = true 23 | @ConfigurationElement(key: "include_compiler_directives") 24 | private(set) var includeCompilerDirectives = true 25 | @ConfigurationElement(key: "include_multiline_strings") 26 | private(set) var includeMultilineStrings = true 27 | } 28 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LegacyObjcTypeConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct LegacyObjcTypeConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = LegacyObjcTypeRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>.warning 9 | @ConfigurationElement(key: "allowed_types") 10 | private(set) var allowedTypes: Set<String> = [] 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct LineLengthConfiguration: RuleConfiguration { 5 | typealias Parent = LineLengthRule 6 | 7 | @ConfigurationElement(inline: true) 8 | private(set) var length = SeverityLevelsConfiguration<Parent>(warning: 120, error: 200) 9 | @ConfigurationElement(key: "ignores_urls") 10 | private(set) var ignoresURLs = false 11 | @ConfigurationElement(key: "ignores_function_declarations") 12 | private(set) var ignoresFunctionDeclarations = false 13 | @ConfigurationElement(key: "ignores_comments") 14 | private(set) var ignoresComments = false 15 | @ConfigurationElement(key: "ignores_interpolated_strings") 16 | private(set) var ignoresInterpolatedStrings = false 17 | @ConfigurationElement(key: "ignores_multiline_strings") 18 | private(set) var ignoresMultilineStrings = false 19 | @ConfigurationElement(key: "excluded_lines_patterns") 20 | private(set) var excludedLinesPatterns: Set<String> = [] 21 | 22 | var params: [RuleParameter<Int>] { 23 | length.params 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | import SwiftLintCore 3 | 4 | @AutoConfigParser 5 | struct ModifierOrderConfiguration: SeverityBasedRuleConfiguration { 6 | typealias Parent = ModifierOrderRule 7 | 8 | @ConfigurationElement(key: "severity") 9 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 10 | @ConfigurationElement(key: "preferred_modifier_order") 11 | private(set) var preferredModifierOrder: [SwiftDeclarationAttributeKind.ModifierGroup] = [ 12 | .override, 13 | .acl, 14 | .setterACL, 15 | .dynamic, 16 | .mutators, 17 | .lazy, 18 | .final, 19 | .required, 20 | .convenience, 21 | .typeMethods, 22 | .owned, 23 | ] 24 | } 25 | 26 | extension SwiftDeclarationAttributeKind.ModifierGroup: AcceptableByConfigurationElement { 27 | public init(fromAny value: Any, context ruleID: String) throws { 28 | if let value = value as? String, let newSelf = Self(rawValue: value), newSelf != .atPrefixed { 29 | self = newSelf 30 | } else { 31 | throw Issue.invalidConfiguration(ruleID: ruleID) 32 | } 33 | } 34 | 35 | public func asOption() -> OptionType { .symbol(rawValue) } 36 | } 37 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineArgumentsConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct MultilineArgumentsConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = MultilineArgumentsRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum FirstArgumentLocation: String { 9 | case anyLine = "any_line" 10 | case sameLine = "same_line" 11 | case nextLine = "next_line" 12 | } 13 | 14 | @ConfigurationElement(key: "severity") 15 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 16 | @ConfigurationElement(key: "first_argument_location") 17 | private(set) var firstArgumentLocation = FirstArgumentLocation.anyLine 18 | @ConfigurationElement(key: "only_enforce_after_first_closure_on_first_line") 19 | private(set) var onlyEnforceAfterFirstClosureOnFirstLine = false 20 | } 21 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct NoEmptyBlockConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = NoEmptyBlockRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum CodeBlockType: String, CaseIterable { 9 | case functionBodies = "function_bodies" 10 | case initializerBodies = "initializer_bodies" 11 | case statementBlocks = "statement_blocks" 12 | case closureBlocks = "closure_blocks" 13 | 14 | static let all = Set(allCases) 15 | } 16 | 17 | @ConfigurationElement(key: "severity") 18 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 19 | 20 | @ConfigurationElement(key: "disabled_block_types") 21 | private(set) var disabledBlockTypes: [CodeBlockType] = [] 22 | 23 | var enabledBlockTypes: Set<CodeBlockType> { 24 | CodeBlockType.all.subtracting(disabledBlockTypes) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoMagicNumbersConfiguration.swift: -------------------------------------------------------------------------------- 1 | @AutoConfigParser 2 | struct NoMagicNumbersConfiguration: SeverityBasedRuleConfiguration { 3 | typealias Parent = NoMagicNumbersRule 4 | 5 | @ConfigurationElement(key: "severity") 6 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 7 | @ConfigurationElement( 8 | key: "test_parent_classes", 9 | postprocessor: { $0.formUnion(["QuickSpec", "XCTestCase"]) } 10 | ) 11 | private(set) var testParentClasses = Set<String>() 12 | @ConfigurationElement( 13 | key: "allowed_numbers", 14 | postprocessor: { $0.formUnion([0, 1, 100]) } 15 | ) 16 | private(set) var allowedNumbers = Set<Double>() 17 | } 18 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NonOverridableClassDeclarationConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser // swiftlint:disable:next type_name 4 | struct NonOverridableClassDeclarationConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = NonOverridableClassDeclarationRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum FinalClassModifier: String { 9 | case finalClass = "final class" 10 | case `static` = "static" 11 | } 12 | 13 | @ConfigurationElement(key: "severity") 14 | private(set) var severityConfiguration = SeverityConfiguration<Parent>.warning 15 | @ConfigurationElement(key: "final_class_modifier") 16 | private(set) var finalClassModifier = FinalClassModifier.finalClass 17 | } 18 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ObjectLiteralConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | typealias DiscouragedObjectLiteralConfiguration = ObjectLiteralConfiguration<DiscouragedObjectLiteralRule> 4 | 5 | @AutoConfigParser 6 | struct ObjectLiteralConfiguration<Parent: Rule>: SeverityBasedRuleConfiguration { 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "image_literal") 10 | private(set) var imageLiteral = true 11 | @ConfigurationElement(key: "color_literal") 12 | private(set) var colorLiteral = true 13 | } 14 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct OpeningBraceConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = OpeningBraceRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "ignore_multiline_type_headers") 10 | private(set) var ignoreMultilineTypeHeaders = false 11 | @ConfigurationElement(key: "ignore_multiline_statement_conditions") 12 | private(set) var ignoreMultilineStatementConditions = false 13 | @ConfigurationElement(key: "ignore_multiline_function_signatures") 14 | private(set) var ignoreMultilineFunctionSignatures = false 15 | // TODO: [08/23/2026] Remove deprecation warning after ~2 years. 16 | @ConfigurationElement(key: "allow_multiline_func", deprecationNotice: .suggestAlternative( 17 | ruleID: Parent.identifier, name: "ignore_multiline_function_signatures")) 18 | private(set) var allowMultilineFunc = false 19 | 20 | var shouldIgnoreMultilineFunctionSignatures: Bool { 21 | ignoreMultilineFunctionSignatures || allowMultilineFunc 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OperatorUsageWhitespaceConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct OperatorUsageWhitespaceConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = OperatorUsageWhitespaceRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "lines_look_around") 10 | private(set) var linesLookAround = 2 11 | @ConfigurationElement(key: "skip_aligned_constants") 12 | private(set) var skipAlignedConstants = true 13 | @ConfigurationElement(key: "allowed_no_space_operators") 14 | private(set) var allowedNoSpaceOperators = ["...", "..<"] 15 | } 16 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PreferKeyPathConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct PreferKeyPathConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = PreferKeyPathRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "restrict_to_standard_functions") 10 | private(set) var restrictToStandardFunctions = true 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrefixedTopLevelConstantConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct PrefixedTopLevelConstantConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = PrefixedTopLevelConstantRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "only_private") 10 | private(set) var onlyPrivateMembers = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateOutletConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct PrivateOutletConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = PrivateOutletRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "allow_private_set") 10 | private(set) var allowPrivateSet = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateOverFilePrivateConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct PrivateOverFilePrivateConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = PrivateOverFilePrivateRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "validate_extensions") 10 | var validateExtensions = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ProhibitedSuperConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct ProhibitedSuperConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = ProhibitedSuperRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "excluded") 10 | private(set) var excluded = [String]() 11 | @ConfigurationElement(key: "included") 12 | private(set) var included = ["*"] 13 | 14 | private static let methodNames = [ 15 | // NSFileProviderExtension 16 | "providePlaceholder(at:completionHandler:)", 17 | // NSTextInput 18 | "doCommand(by:)", 19 | // NSView 20 | "updateLayer()", 21 | // UIViewController 22 | "loadView()", 23 | ] 24 | 25 | var resolvedMethodNames: [String] { 26 | var names = [String]() 27 | if included.contains("*"), !excluded.contains("*") { 28 | names += Self.methodNames 29 | } 30 | names += included.filter { $0 != "*" } 31 | names = names.filter { !excluded.contains($0) } 32 | return names 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantDiscardableLetConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct RedundantDiscardableLetConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = RedundantDiscardableLetRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "ignore_swiftui_view_bodies") 10 | private(set) var ignoreSwiftUIViewBodies = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantSendableConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct RedundantSendableConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = RedundantSendableRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "global_actors") 10 | private(set) var globalActors = Set<String>() 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct RedundantTypeAnnotationConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = RedundantTypeAnnotationRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "ignore_attributes") 10 | var ignoreAttributes = Set<String>(["IBInspectable"]) 11 | @ConfigurationElement(key: "ignore_properties") 12 | private(set) var ignoreProperties = false 13 | @ConfigurationElement(key: "consider_default_literal_types_redundant") 14 | private(set) var considerDefaultLiteralTypesRedundant = false 15 | } 16 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantVoidReturnConfiguration.swift: -------------------------------------------------------------------------------- 1 | @AutoConfigParser 2 | struct RedundantVoidReturnConfiguration: SeverityBasedRuleConfiguration { 3 | typealias Parent = RedundantVoidReturnRule 4 | 5 | @ConfigurationElement(key: "severity") 6 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 7 | @ConfigurationElement(key: "include_closures") 8 | private(set) var includeClosures = true 9 | } 10 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SelfBindingConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct SelfBindingConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = SelfBindingRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "bind_identifier") 10 | private(set) var bindIdentifier = "self" 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ShorthandArgumentConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct ShorthandArgumentConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = ShorthandArgumentRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "allow_until_line_after_opening_brace") 10 | private(set) var allowUntilLineAfterOpeningBrace = 4 11 | @ConfigurationElement(key: "always_disallow_more_than_one") 12 | private(set) var alwaysDisallowMoreThanOne = false 13 | @ConfigurationElement(key: "always_disallow_member_access") 14 | private(set) var alwaysDisallowMemberAccess = false 15 | } 16 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SortedImportsConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct SortedImportsConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = SortedImportsRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum SortedImportsGroupingConfiguration: String { 9 | /// Sorts import lines based on any import attributes (e.g. `@testable`, `@_exported`, etc.), followed by a case 10 | /// insensitive comparison of the imported module name. 11 | case attributes 12 | /// Sorts import lines based on a case insensitive comparison of the imported module name. 13 | case names 14 | } 15 | 16 | @ConfigurationElement(key: "severity") 17 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 18 | @ConfigurationElement(key: "grouping") 19 | private(set) var grouping = SortedImportsGroupingConfiguration.names 20 | } 21 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/StatementPositionConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct StatementPositionConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = StatementPositionRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum StatementModeConfiguration: String { 9 | case `default` = "default" 10 | case uncuddledElse = "uncuddled_else" 11 | } 12 | 13 | @ConfigurationElement(key: "severity") 14 | private(set) var severityConfiguration = SeverityConfiguration<Parent>.warning 15 | @ConfigurationElement(key: "statement_mode") 16 | private(set) var statementMode = StatementModeConfiguration.default 17 | } 18 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SwitchCaseAlignmentConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct SwitchCaseAlignmentConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = SwitchCaseAlignmentRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "indented_cases") 10 | private(set) var indentedCases = false 11 | @ConfigurationElement(key: "ignore_one_liners") 12 | private(set) var ignoreOneLiners = false 13 | } 14 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TestCaseAccessibilityConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct TestCaseAccessibilityConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = TestCaseAccessibilityRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "allowed_prefixes") 10 | private(set) var allowedPrefixes: Set<String> = [] 11 | @ConfigurationElement( 12 | key: "test_parent_classes", 13 | postprocessor: { $0.formUnion(["QuickSpec", "XCTestCase"]) } 14 | ) 15 | private(set) var testParentClasses = Set<String>() 16 | } 17 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TodoConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct TodoConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = TodoRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum TodoKeyword: String, CaseIterable { 9 | case todo = "TODO" 10 | case fixme = "FIXME" 11 | } 12 | 13 | @ConfigurationElement(key: "severity") 14 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 15 | @ConfigurationElement(key: "only") 16 | private(set) var only = TodoKeyword.allCases 17 | } 18 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingClosureConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct TrailingClosureConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = TrailingClosureRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "only_single_muted_parameter") 10 | private(set) var onlySingleMutedParameter = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingCommaConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct TrailingCommaConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = TrailingCommaRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "mandatory_comma") 10 | private(set) var mandatoryComma = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingWhitespaceConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct TrailingWhitespaceConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = TrailingWhitespaceRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "ignores_empty_lines") 10 | private(set) var ignoresEmptyLines = false 11 | @ConfigurationElement(key: "ignores_comments") 12 | private(set) var ignoresComments = true 13 | } 14 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeBodyLengthConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AcceptableByConfigurationElement 4 | enum TypeBodyLengthCheckType: String, CaseIterable, Comparable { 5 | case `actor` = "actor" 6 | case `class` = "class" 7 | case `enum` = "enum" 8 | case `extension` = "extension" 9 | case `protocol` = "protocol" 10 | case `struct` = "struct" 11 | 12 | static func < (lhs: Self, rhs: Self) -> Bool { 13 | lhs.rawValue < rhs.rawValue 14 | } 15 | } 16 | 17 | @AutoConfigParser 18 | struct TypeBodyLengthConfiguration: SeverityLevelsBasedRuleConfiguration { 19 | typealias Parent = TypeBodyLengthRule 20 | 21 | @ConfigurationElement(inline: true) 22 | private(set) var severityConfiguration = SeverityLevelsConfiguration<Parent>(warning: 250, error: 350) 23 | @ConfigurationElement(key: "excluded_types") 24 | private(set) var excludedTypes = Set<TypeBodyLengthCheckType>([.extension, .protocol]) 25 | } 26 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeNameConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct TypeNameConfiguration: RuleConfiguration { 5 | typealias Parent = TypeNameRule 6 | 7 | @ConfigurationElement(inline: true) 8 | private(set) var nameConfiguration = NameConfiguration<Parent>(minLengthWarning: 3, 9 | minLengthError: 0, 10 | maxLengthWarning: 40, 11 | maxLengthError: 1000) 12 | @ConfigurationElement(key: "validate_protocols") 13 | private(set) var validateProtocols = true 14 | } 15 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnitTestConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | typealias BalancedXCTestLifecycleConfiguration = UnitTestConfiguration<BalancedXCTestLifecycleRule> 4 | typealias EmptyXCTestMethodConfiguration = UnitTestConfiguration<EmptyXCTestMethodRule> 5 | typealias FinalTestCaseConfiguration = UnitTestConfiguration<FinalTestCaseRule> 6 | typealias SingleTestClassConfiguration = UnitTestConfiguration<SingleTestClassRule> 7 | typealias PrivateUnitTestConfiguration = UnitTestConfiguration<PrivateUnitTestRule> 8 | 9 | @AutoConfigParser 10 | struct UnitTestConfiguration<Parent: Rule>: SeverityBasedRuleConfiguration { 11 | @ConfigurationElement(key: "severity") 12 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 13 | @ConfigurationElement( 14 | key: "test_parent_classes", 15 | postprocessor: { $0.formUnion(["QuickSpec", "XCTestCase"]) } 16 | ) 17 | private(set) var testParentClasses = Set<String>() 18 | } 19 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnneededOverrideRuleConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct UnneededOverrideRuleConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = UnneededOverrideRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "affect_initializers") 10 | private(set) var affectInits = false 11 | @ConfigurationElement(key: "excluded_methods") 12 | private(set) var excludedMethods = Set<String>() 13 | } 14 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedDeclarationConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct UnusedDeclarationConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = UnusedDeclarationRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>.error 9 | @ConfigurationElement(key: "include_public_and_open") 10 | private(set) var includePublicAndOpen = false 11 | @ConfigurationElement( 12 | key: "related_usrs_to_skip", 13 | postprocessor: { $0.insert("s:7SwiftUI15PreviewProviderP") } 14 | ) 15 | private(set) var relatedUSRsToSkip = Set<String>() 16 | } 17 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedOptionalBindingConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct UnusedOptionalBindingConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = UnusedOptionalBindingRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "ignore_optional_try") 10 | private(set) var ignoreOptionalTry = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/VerticalWhitespaceClosingBracesConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser // swiftlint:disable:next type_name 4 | struct VerticalWhitespaceClosingBracesConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = VerticalWhitespaceClosingBracesRule 6 | 7 | @ConfigurationElement(key: "severity") 8 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 9 | @ConfigurationElement(key: "only_enforce_before_trivial_lines") 10 | private(set) var onlyEnforceBeforeTrivialLines = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/VerticalWhitespaceConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct VerticalWhitespaceConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = VerticalWhitespaceRule 6 | 7 | static let defaultDescriptionReason = "Limit vertical whitespace to a single empty line" 8 | 9 | @ConfigurationElement(key: "severity") 10 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 11 | @ConfigurationElement(key: "max_empty_lines") 12 | private(set) var maxEmptyLines = 1 13 | 14 | var configuredDescriptionReason: String { 15 | guard maxEmptyLines == 1 else { 16 | return "Limit vertical whitespace to maximum \(maxEmptyLines) empty lines" 17 | } 18 | return Self.defaultDescriptionReason 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/XCTSpecificMatcherConfiguration.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | @AutoConfigParser 4 | struct XCTSpecificMatcherConfiguration: SeverityBasedRuleConfiguration { 5 | typealias Parent = XCTSpecificMatcherRule 6 | 7 | @AcceptableByConfigurationElement 8 | enum Matcher: String, CaseIterable { 9 | case oneArgumentAsserts = "one-argument-asserts" 10 | case twoArgumentAsserts = "two-argument-asserts" 11 | } 12 | 13 | @ConfigurationElement(key: "severity") 14 | private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning) 15 | @ConfigurationElement(key: "matchers") 16 | private(set) var matchers = Matcher.allCases 17 | } 18 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Extensions/ByteCount+SwiftSyntax.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | import SwiftSyntax 3 | 4 | public extension ByteCount { 5 | /// Converts a SwiftSyntax `AbsolutePosition` to a SourceKitten `ByteCount`. 6 | /// 7 | /// - parameter position: The SwiftSyntax position to convert. 8 | init(_ position: AbsolutePosition) { 9 | self.init(position.utf8Offset) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Extensions/NSRange+SwiftLint.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension NSRange { 4 | func intersects(_ range: NSRange) -> Bool { 5 | NSIntersectionRange(self, range).length > 0 6 | } 7 | 8 | func intersects(_ ranges: [NSRange]) -> Bool { 9 | for range in ranges where intersects(range) { 10 | return true 11 | } 12 | return false 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Extensions/SourceRange+SwiftLint.swift: -------------------------------------------------------------------------------- 1 | import SwiftSyntax 2 | 3 | public extension SourceRange { 4 | /// Check if a position is contained within this range. 5 | /// 6 | /// - parameter position: The position to check. 7 | /// - parameter locationConverter: The location converter to use to perform the check. 8 | /// 9 | /// - returns: Whether the specified position is contained within this range. 10 | func contains(_ position: AbsolutePosition, locationConverter: SourceLocationConverter) -> Bool { 11 | let startPosition = locationConverter.position(ofLine: start.line, column: start.column) 12 | let endPosition = locationConverter.position(ofLine: end.line, column: end.column) 13 | return startPosition <= position && position <= endPosition 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Extensions/StringView+SwiftLint.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | 3 | public extension StringView { 4 | /// Converts a line and column position in a code snippet to a byte offset. 5 | /// - Parameters: 6 | /// - line: Line in code snippet 7 | /// - bytePosition: Byte position in line 8 | /// - Returns: Byte offset coinciding with the line and the column given 9 | func byteOffset(forLine line: Int64, bytePosition: Int64) -> ByteCount? { 10 | guard line > 0, line <= lines.count, bytePosition > 0 else { 11 | return nil 12 | } 13 | return lines[Int(line) - 1].byteRange.location + ByteCount(bytePosition - 1) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Extensions/StringView+SwiftSyntax.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceKittenFramework 3 | import SwiftSyntax 4 | 5 | public extension StringView { 6 | /// Converts two absolute positions from SwiftSyntax to a valid `NSRange` if possible. 7 | /// 8 | /// - parameter start: Starting position. 9 | /// - parameter end: End position. 10 | /// 11 | /// - returns: `NSRange` or nil in case of empty string. 12 | func NSRange(start: AbsolutePosition, end: AbsolutePosition) -> NSRange? { 13 | precondition(end >= start, "End position should be bigger than the start position") 14 | return NSRange(start: start, length: ByteCount(end.utf8Offset - start.utf8Offset)) 15 | } 16 | 17 | /// Converts absolute position with length from SwiftSyntax to a valid `NSRange` if possible. 18 | /// 19 | /// - parameter start: Starting position. 20 | /// - parameter length: Length in bytes. 21 | /// 22 | /// - returns: `NSRange` or nil in case of empty string. 23 | private func NSRange(start: AbsolutePosition, length: ByteCount) -> NSRange? { 24 | let byteRange = ByteRange(location: ByteCount(start), length: length) 25 | return byteRangeToNSRange(byteRange) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Extensions/SwiftDeclarationKind+SwiftLint.swift: -------------------------------------------------------------------------------- 1 | @preconcurrency import SourceKittenFramework 2 | 3 | public extension SwiftDeclarationKind { 4 | static let functionKinds: Set<SwiftDeclarationKind> = [ 5 | .functionAccessorAddress, 6 | .functionAccessorDidset, 7 | .functionAccessorGetter, 8 | .functionAccessorMutableaddress, 9 | .functionAccessorSetter, 10 | .functionAccessorWillset, 11 | .functionConstructor, 12 | .functionDestructor, 13 | .functionFree, 14 | .functionMethodClass, 15 | .functionMethodInstance, 16 | .functionMethodStatic, 17 | .functionOperator, 18 | .functionSubscript, 19 | ] 20 | 21 | static let typeKinds: Set<SwiftDeclarationKind> = [ 22 | .class, 23 | .struct, 24 | .typealias, 25 | .associatedtype, 26 | .enum, 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Extensions/SyntaxClassification+isComment.swift: -------------------------------------------------------------------------------- 1 | import SwiftIDEUtils 2 | 3 | public extension SyntaxClassification { 4 | // True if it is any kind of comment. 5 | var isComment: Bool { 6 | switch self { 7 | case .lineComment, .docLineComment, .blockComment, .docBlockComment: 8 | return true 9 | case .none, .keyword, .identifier, .type, .operator, .dollarIdentifier, .integerLiteral, .argumentLabel, 10 | .floatLiteral, .stringLiteral, .ifConfigDirective, .attribute, .editorPlaceholder, .regexLiteral: 11 | return false 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Models/ConfigurationRuleWrapper.swift: -------------------------------------------------------------------------------- 1 | package typealias ConfigurationRuleWrapper = (rule: any Rule, initializedWithNonEmptyConfiguration: Bool) 2 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Models/Correction.swift: -------------------------------------------------------------------------------- 1 | /// A value describing a SwiftLint violation that was corrected. 2 | public struct Correction: Equatable, Sendable { 3 | /// The name of the rule that was corrected. 4 | public let ruleName: String 5 | /// The path to the file that was corrected. 6 | public let filePath: String? 7 | /// The number of corrections that were made. 8 | public let numberOfCorrections: Int 9 | 10 | /// The console-printable description for this correction. 11 | public var consoleDescription: String { 12 | let times = numberOfCorrections == 1 ? "time" : "times" 13 | return "\(filePath ?? "<nopath>"): Corrected \(ruleName) \(numberOfCorrections) \(times)" 14 | } 15 | 16 | /// Memberwise initializer. 17 | /// 18 | /// - parameter ruleName: The name of the rule that was corrected. 19 | /// - parameter filePath: The path to the file that was corrected. 20 | /// - parameter numberOfCorrections: The number of corrections that were made. 21 | public init(ruleName: String, filePath: String?, numberOfCorrections: Int) { 22 | self.ruleName = ruleName 23 | self.filePath = filePath 24 | self.numberOfCorrections = numberOfCorrections 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Models/CurrentRule.swift: -------------------------------------------------------------------------------- 1 | /// A task-local value that holds the identifier of the currently executing rule. 2 | /// This allows SourceKit request handling to determine if the current rule 3 | /// is a SourceKitFreeRule without modifying function signatures throughout the codebase. 4 | public enum CurrentRule { 5 | /// The Rule ID for the currently executing rule. 6 | @TaskLocal public static var identifier: String? 7 | 8 | /// Allows specific SourceKit requests to be made outside of rule execution context. 9 | /// This should only be used for essential operations like getting the Swift version. 10 | @TaskLocal public static var allowSourceKitRequestWithoutRule = false 11 | } 12 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Models/RuleKind.swift: -------------------------------------------------------------------------------- 1 | /// All the possible rule kinds (categories). 2 | public enum RuleKind: String, CaseIterable, Codable, Sendable { 3 | /// Describes rules that validate Swift source conventions. 4 | case lint 5 | /// Describes rules that validate common practices in the Swift community. 6 | case idiomatic 7 | /// Describes rules that validate stylistic choices. 8 | case style 9 | /// Describes rules that validate magnitudes or measurements of Swift source. 10 | case metrics 11 | /// Describes rules that validate that code patterns with poor performance are avoided. 12 | case performance 13 | } 14 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Models/RuleParameter.swift: -------------------------------------------------------------------------------- 1 | /// A configuration parameter for rules. 2 | public struct RuleParameter<T: Equatable>: Equatable { 3 | /// The severity that should be assigned to the violation of this parameter's value is met. 4 | public let severity: ViolationSeverity 5 | /// The value to configure the rule. 6 | public let value: T 7 | 8 | /// Creates a `RuleParameter` by specifying its properties directly. 9 | /// 10 | /// - parameter severity: The severity that should be assigned to the violation of this parameter's value is met. 11 | /// - parameter value: The value to configure the rule. 12 | public init(severity: ViolationSeverity, value: T) { 13 | self.severity = severity 14 | self.value = value 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Models/RuleRegistry.swift: -------------------------------------------------------------------------------- 1 | /// Container to register and look up SwiftLint rules. 2 | public final class RuleRegistry: @unchecked Sendable { 3 | private var registeredRules = [any Rule.Type]() 4 | 5 | /// Shared rule registry instance. 6 | public static let shared = RuleRegistry() 7 | 8 | /// Rule list associated with this registry. Lazily created, and 9 | /// immutable once looked up. 10 | /// 11 | /// - note: Adding registering more rules after this was first 12 | /// accessed will not work. 13 | public private(set) lazy var list = RuleList(rules: registeredRules) 14 | 15 | private init() { /* To guarantee that this is singleton. */ } 16 | 17 | /// Register rules. 18 | /// 19 | /// - parameter rules: The rules to register. 20 | public func register(rules: [any Rule.Type]) { 21 | registeredRules.append(contentsOf: rules) 22 | } 23 | 24 | /// Look up a rule for a given ID. 25 | /// 26 | /// - parameter id: The ID for the rule to look up. 27 | /// 28 | /// - returns: The rule matching the specified ID, if one was found. 29 | public func rule(forID id: String) -> (any Rule.Type)? { 30 | list.list[id] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Models/SwiftExpressionKind.swift: -------------------------------------------------------------------------------- 1 | /// The kind of expression for a contiguous set of Swift source tokens. 2 | public enum SwiftExpressionKind: String { 3 | /// A call to a named function or closure. 4 | case call = "source.lang.swift.expr.call" 5 | /// An argument value for a function or closure. 6 | case argument = "source.lang.swift.expr.argument" 7 | /// An Array expression. 8 | case array = "source.lang.swift.expr.array" 9 | /// A Dictionary expression. 10 | case dictionary = "source.lang.swift.expr.dictionary" 11 | /// An object literal expression. https://developer.apple.com/swift/blog/?id=33 12 | case objectLiteral = "source.lang.swift.expr.object_literal" 13 | /// A closure expression. https://docs.swift.org/swift-book/LanguageGuide/Closures.html 14 | case closure = "source.lang.swift.expr.closure" 15 | /// A tuple expression. https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID448 16 | case tuple = "source.lang.swift.expr.tuple" 17 | } 18 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Models/SwiftLintSyntaxToken.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | 3 | /// A SwiftLint-aware Swift syntax token. 4 | public struct SwiftLintSyntaxToken { 5 | /// The raw `SyntaxToken` obtained by SourceKitten. 6 | public let value: SyntaxToken 7 | 8 | /// The syntax kind associated with is token. 9 | public let kind: SyntaxKind? 10 | 11 | /// Creates a `SwiftLintSyntaxToken` from the raw `SyntaxToken` obtained by SourceKitten. 12 | /// 13 | /// - parameter value: The raw `SyntaxToken` obtained by SourceKitten. 14 | public init(value: SyntaxToken) { 15 | self.value = value 16 | kind = SyntaxKind(rawValue: value.type) 17 | } 18 | 19 | /// The byte range in a source file for this token. 20 | public var range: ByteRange { 21 | value.range 22 | } 23 | 24 | /// The starting byte offset in a source file for this token. 25 | public var offset: ByteCount { 26 | value.offset 27 | } 28 | 29 | /// The length in bytes for this token. 30 | public var length: ByteCount { 31 | value.length 32 | } 33 | } 34 | 35 | public extension Array where Element == SwiftLintSyntaxToken { 36 | /// The kinds for these tokens. 37 | var kinds: [SyntaxKind] { 38 | compactMap(\.kind) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Models/ViolationSeverity.swift: -------------------------------------------------------------------------------- 1 | /// The magnitude of a `StyleViolation`. 2 | @AcceptableByConfigurationElement 3 | public enum ViolationSeverity: String, Comparable, CaseIterable, Codable, Sendable, InlinableOptionType { 4 | /// Non-fatal. If using SwiftLint as an Xcode build phase, Xcode will mark the build as having succeeded. 5 | case warning 6 | /// Fatal. If using SwiftLint as an Xcode build phase, Xcode will mark the build as having failed. 7 | case error 8 | 9 | // MARK: Comparable 10 | 11 | public static func < (lhs: Self, rhs: Self) -> Bool { 12 | lhs == .warning && rhs == .error 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/SwiftLintCore/Protocols/CacheDescriptionProvider.swift: -------------------------------------------------------------------------------- 1 | /// Interface providing access to a cache description. 2 | public protocol CacheDescriptionProvider { 3 | /// The cache description which will be used to determine if a previous 4 | /// cached value is still valid given the new cache value. 5 | var cacheDescription: String { get } 6 | } 7 | -------------------------------------------------------------------------------- /Source/SwiftLintCoreMacros/SwiftLintCoreMacros.swift: -------------------------------------------------------------------------------- 1 | import SwiftCompilerPlugin 2 | import SwiftDiagnostics 3 | import SwiftSyntax 4 | import SwiftSyntaxMacros 5 | 6 | @main 7 | struct SwiftLintCoreMacros: CompilerPlugin { 8 | let providingMacros: [any Macro.Type] = [ 9 | AutoConfigParser.self, 10 | AcceptableByConfigurationElement.self, 11 | SwiftSyntaxRule.self, 12 | ] 13 | } 14 | 15 | enum SwiftLintCoreMacroError: String, DiagnosticMessage { 16 | case notStruct = "Attribute can only be applied to structs" 17 | case severityBasedWithoutProperty = """ 18 | Severity-based configuration without a 'severityConfiguration' property is invalid 19 | """ 20 | case notEnum = "Attribute can only be applied to enums" 21 | case noStringRawType = "Attribute can only be applied to enums with a 'String' raw type" 22 | case noBooleanLiteral = "Macro argument must be a boolean literal" 23 | 24 | var message: String { 25 | rawValue 26 | } 27 | 28 | var diagnosticID: MessageID { 29 | MessageID(domain: "SwiftLint", id: "SwiftLintCoreMacro.\(self)") 30 | } 31 | 32 | var severity: DiagnosticSeverity { 33 | .error 34 | } 35 | 36 | func diagnose(at node: some SyntaxProtocol) -> Diagnostic { 37 | Diagnostic(node: Syntax(node), message: self) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/SwiftLintExtraRules/Exports.swift: -------------------------------------------------------------------------------- 1 | @_exported import SwiftLintCore 2 | -------------------------------------------------------------------------------- /Source/SwiftLintExtraRules/ExtraRules.swift: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT 2 | 3 | /// This is an extension point for custom native rules for Bazel. 4 | /// 5 | /// - returns: Extra rules that are compiled with Bazel. 6 | public func extraRules() -> [any Rule.Type] { [] } 7 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Configuration/Configuration+IndentationStyle.swift: -------------------------------------------------------------------------------- 1 | public extension Configuration { 2 | /// The style of indentation used in a Swift project. 3 | enum IndentationStyle: Hashable, Sendable { 4 | /// Swift source code should be indented using tabs. 5 | case tabs 6 | /// Swift source code should be indented using spaces with `count` spaces per indentation level. 7 | case spaces(count: Int) 8 | 9 | /// The default indentation style if none is explicitly provided. 10 | package static let `default` = spaces(count: 4) 11 | 12 | /// Creates an indentation style based on an untyped configuration value. 13 | /// 14 | /// - parameter object: The configuration value. 15 | internal init?(_ object: Any?) { 16 | switch object { 17 | case let value as Int: self = .spaces(count: value) 18 | case let value as String where value == "tabs": self = .tabs 19 | default: return nil 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Exports.swift: -------------------------------------------------------------------------------- 1 | @_exported import SwiftLintBuiltInRules 2 | @_exported import SwiftLintCore 3 | import SwiftLintExtraRules 4 | 5 | private let _registerAllRulesOnceImpl: Void = { 6 | RuleRegistry.shared.register(rules: builtInRules + coreRules + extraRules()) 7 | }() 8 | 9 | package extension RuleRegistry { 10 | /// Register all rules. Should only be called once before any SwiftLint code is executed. 11 | static func registerAllRulesOnce() { 12 | _ = _registerAllRulesOnceImpl 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Extensions/String+XML.swift: -------------------------------------------------------------------------------- 1 | extension String { 2 | func escapedForXML() -> String { 3 | // & needs to go first, otherwise other replacements will be replaced again 4 | let htmlEscapes = [ 5 | ("&", "&"), 6 | ("\"", """), 7 | ("'", "'"), 8 | (">", ">"), 9 | ("<", "<"), 10 | ] 11 | var newString = self 12 | for (key, value) in htmlEscapes { 13 | newString = newString.replacingOccurrences(of: key, with: value) 14 | } 15 | return newString 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Extensions/String+sha256.swift: -------------------------------------------------------------------------------- 1 | #if canImport(CommonCrypto) 2 | import CommonCrypto 3 | import Foundation 4 | 5 | extension Data { 6 | internal func sha256() -> Data { 7 | withUnsafeBytes { bytes in 8 | var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) 9 | _ = CC_SHA256(bytes.baseAddress, CC_LONG(count), &hash) 10 | return Data(hash) 11 | } 12 | } 13 | 14 | internal func toHexString() -> String { 15 | reduce(into: "") { $0.append(String(format: "%02x", $1)) } 16 | } 17 | } 18 | 19 | extension String { 20 | internal func sha256() -> String { 21 | data(using: .utf8)!.sha256().toHexString() 22 | } 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Helpers/ExecutableInfo.swift: -------------------------------------------------------------------------------- 1 | #if os(macOS) 2 | import Foundation 3 | import MachO 4 | #endif 5 | 6 | /// Information about this executable. 7 | public enum ExecutableInfo { 8 | /// A stable identifier for this executable. Uses the Mach-O header UUID on macOS. Nil on Linux. 9 | public static let buildID: String? = { 10 | #if os(macOS) 11 | func getUUID(pointer: UnsafeRawPointer) -> UUID? { 12 | var offset: UInt64 = 0 13 | let header = pointer.bindMemory(to: mach_header_64.self, capacity: 1) 14 | offset += UInt64(MemoryLayout<mach_header_64>.size) 15 | for _ in 0..<header.pointee.ncmds { 16 | let loadCommand = pointer.load(fromByteOffset: Int(offset), as: load_command.self) 17 | if loadCommand.cmd == LC_UUID { 18 | let uuidCommand = pointer.load(fromByteOffset: Int(offset), as: uuid_command.self) 19 | return UUID(uuid: uuidCommand.uuid) 20 | } 21 | offset += UInt64(loadCommand.cmdsize) 22 | } 23 | return nil 24 | } 25 | 26 | if let handle = dlopen(nil, RTLD_LAZY) { 27 | defer { dlclose(handle) } 28 | 29 | if let ptr = dlsym(handle, MH_EXECUTE_SYM) { 30 | return getUUID(pointer: ptr)?.uuidString 31 | } 32 | } 33 | #endif 34 | return nil 35 | }() 36 | } 37 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Models/CustomRuleTimer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Utility to measure the time spent in each custom rule. 4 | public final class CustomRuleTimer: @unchecked Sendable { 5 | private let lock = NSLock() 6 | private var ruleIDForTimes = [String: [TimeInterval]]() 7 | private var shouldRecord = false 8 | 9 | /// Singleton. 10 | public static let shared = CustomRuleTimer() 11 | 12 | /// Tell the timer it should record time spent in rules. 13 | public func activate() { 14 | shouldRecord = true 15 | } 16 | 17 | /// Return all time spent for each custom rule, keyed by rule ID. 18 | public func dump() -> [String: TimeInterval] { 19 | lock.withLock { 20 | ruleIDForTimes.mapValues { $0.reduce(0, +) } 21 | } 22 | } 23 | 24 | /// Register time spent evaluating a rule with the specified ID. 25 | /// 26 | /// - parameter time: The time interval spent evaluating this rule ID. 27 | /// - parameter ruleID: The ID of the rule that was evaluated. 28 | func register(time: TimeInterval, forRuleID ruleID: String) { 29 | if shouldRecord { 30 | lock.withLock { 31 | ruleIDForTimes[ruleID, default: []].append(time) 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Models/HashableConfigurationRuleWrapperWrapper.swift: -------------------------------------------------------------------------------- 1 | internal struct HashableConfigurationRuleWrapperWrapper: Hashable { 2 | let configurationRuleWrapper: ConfigurationRuleWrapper 3 | 4 | static func == ( 5 | lhs: Self, rhs: Self 6 | ) -> Bool { 7 | // Only use identifier for equality check (not taking config into account) 8 | type(of: lhs.configurationRuleWrapper.rule).identifier 9 | == type(of: rhs.configurationRuleWrapper.rule).identifier 10 | } 11 | 12 | func hash(into hasher: inout Hasher) { 13 | hasher.combine(type(of: configurationRuleWrapper.rule).identifier) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Models/ReportersList.swift: -------------------------------------------------------------------------------- 1 | // GENERATED FILE. DO NOT EDIT! 2 | 3 | /// The reporters list containing all the reporters built into SwiftLint. 4 | public let reportersList: [any Reporter.Type] = [ 5 | CSVReporter.self, 6 | CheckstyleReporter.self, 7 | CodeClimateReporter.self, 8 | EmojiReporter.self, 9 | GitHubActionsLoggingReporter.self, 10 | GitLabJUnitReporter.self, 11 | HTMLReporter.self, 12 | JSONReporter.self, 13 | JUnitReporter.self, 14 | MarkdownReporter.self, 15 | RelativePathReporter.self, 16 | SARIFReporter.self, 17 | SonarQubeReporter.self, 18 | SummaryReporter.self, 19 | XcodeReporter.self, 20 | ] 21 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Models/Version.swift: -------------------------------------------------------------------------------- 1 | /// A type describing the SwiftLint version. 2 | public struct Version: VersionComparable, Sendable { 3 | /// The string value for this version. 4 | public let value: String 5 | 6 | /// An alias for `value` required for protocol conformance. 7 | public var rawValue: String { 8 | value 9 | } 10 | 11 | /// The current SwiftLint version. 12 | public static let current = Self(value: "0.59.1") 13 | 14 | /// Public initializer. 15 | /// 16 | /// - parameter value: The string value for this version. 17 | public init(value: String) { 18 | self.value = value 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/ProcessInfo+XcodeCloud.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension ProcessInfo { 4 | var isLikelyXcodeCloudEnvironment: Bool { 5 | // https://developer.apple.com/documentation/xcode/environment-variable-reference 6 | let requiredKeys: Set = [ 7 | "CI", 8 | "CI_BUILD_ID", 9 | "CI_BUILD_NUMBER", 10 | "CI_BUNDLE_ID", 11 | "CI_COMMIT", 12 | "CI_DERIVED_DATA_PATH", 13 | "CI_PRODUCT", 14 | "CI_PRODUCT_ID", 15 | "CI_PRODUCT_PLATFORM", 16 | "CI_PROJECT_FILE_PATH", 17 | "CI_START_CONDITION", 18 | "CI_TEAM_ID", 19 | "CI_WORKFLOW", 20 | "CI_WORKSPACE", 21 | "CI_XCODE_PROJECT", 22 | "CI_XCODE_SCHEME", 23 | "CI_XCODEBUILD_ACTION", 24 | ] 25 | 26 | return requiredKeys.isSubset(of: environment.keys) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Reporters/JSONReporter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SourceKittenFramework 3 | 4 | /// Reports violations as a JSON array. 5 | struct JSONReporter: Reporter { 6 | // MARK: - Reporter Conformance 7 | 8 | static let identifier = "json" 9 | static let isRealtime = false 10 | static let description = "Reports violations as a JSON array." 11 | 12 | static func generateReport(_ violations: [StyleViolation]) -> String { 13 | toJSON(violations.map(dictionary(for:)), options: [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes]) 14 | } 15 | 16 | // MARK: - Private 17 | 18 | private static func dictionary(for violation: StyleViolation) -> [String: Any] { 19 | [ 20 | "file": violation.location.file ?? NSNull() as Any, 21 | "line": violation.location.line ?? NSNull() as Any, 22 | "character": violation.location.character ?? NSNull() as Any, 23 | "severity": violation.severity.rawValue.capitalized, 24 | "type": violation.ruleName, 25 | "rule_id": violation.ruleIdentifier, 26 | "reason": violation.reason, 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Reporters/RelativePathReporter.swift: -------------------------------------------------------------------------------- 1 | /// Reports violations with relative paths. 2 | struct RelativePathReporter: Reporter { 3 | // MARK: - Reporter Conformance 4 | 5 | static let identifier = "relative-path" 6 | static let isRealtime = true 7 | static let description = "Reports violations with relative paths." 8 | 9 | static func generateReport(_ violations: [StyleViolation]) -> String { 10 | violations.map(generateForSingleViolation).joined(separator: "\n") 11 | } 12 | 13 | /// Generates a report for a single violation. 14 | /// 15 | /// - parameter violation: The violation to report. 16 | /// 17 | /// - returns: The report for a single violation. 18 | internal static func generateForSingleViolation(_ violation: StyleViolation) -> String { 19 | // {relative_path_to_file}{:line}{:character}: {error,warning}: {content} 20 | 21 | [ 22 | "\(violation.location.relativeFile ?? "<nopath>")", 23 | ":\(violation.location.line ?? 1)", 24 | ":\(violation.location.character ?? 1): ", 25 | "\(violation.severity.rawValue): ", 26 | "\(violation.ruleName) Violation: ", 27 | violation.reason, 28 | " (\(violation.ruleIdentifier))", 29 | ].joined() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Reporters/SonarQubeReporter.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | 3 | /// Reports violations in SonarQube import format. 4 | struct SonarQubeReporter: Reporter { 5 | // MARK: - Reporter Conformance 6 | 7 | static let identifier = "sonarqube" 8 | static let isRealtime = false 9 | static let description = "Reports violations in SonarQube import format." 10 | 11 | static func generateReport(_ violations: [StyleViolation]) -> String { 12 | toJSON(["issues": violations.map(dictionary(for:))]) 13 | } 14 | 15 | // MARK: - Private 16 | 17 | // refer to https://docs.sonarqube.org/display/SONAR/Generic+Issue+Data 18 | private static func dictionary(for violation: StyleViolation) -> [String: Any] { 19 | [ 20 | "engineId": "SwiftLint", 21 | "ruleId": violation.ruleIdentifier, 22 | "primaryLocation": [ 23 | "message": violation.reason, 24 | "filePath": violation.location.relativeFile ?? "", 25 | "textRange": [ 26 | "startLine": violation.location.line ?? 1 27 | ] as Any, 28 | ] as Any, 29 | "type": "CODE_SMELL", 30 | "severity": violation.severity == .error ? "MAJOR" : "MINOR", 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Reporters/XcodeReporter.swift: -------------------------------------------------------------------------------- 1 | /// Reports violations in the format Xcode uses to display in the IDE. (default) 2 | struct XcodeReporter: Reporter { 3 | // MARK: - Reporter Conformance 4 | 5 | static let identifier = "xcode" 6 | static let isRealtime = true 7 | static let description = "Reports violations in the format Xcode uses to display in the IDE. (default)" 8 | 9 | static func generateReport(_ violations: [StyleViolation]) -> String { 10 | violations.map(generateForSingleViolation).joined(separator: "\n") 11 | } 12 | 13 | /// Generates a report for a single violation. 14 | /// 15 | /// - parameter violation: The violation to report. 16 | /// 17 | /// - returns: The report for a single violation. 18 | internal static func generateForSingleViolation(_ violation: StyleViolation) -> String { 19 | violation.description 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/Rules/CoreRules.swift: -------------------------------------------------------------------------------- 1 | /// The rule list containing all available rules built into SwiftLintCore. 2 | public let coreRules: [any Rule.Type] = [ 3 | CustomRules.self, 4 | SuperfluousDisableCommandRule.self, 5 | ] 6 | -------------------------------------------------------------------------------- /Source/SwiftLintFramework/SwiftLintError.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | package enum SwiftLintError: LocalizedError { 4 | case usageError(description: String) 5 | 6 | package var errorDescription: String? { 7 | switch self { 8 | case .usageError(let description): 9 | return description 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Source/YamsWrapper/Empty.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realm/SwiftLint/c1ffdfe8913c12398a3a05fe19844c1031fa7add/Source/YamsWrapper/Empty.swift -------------------------------------------------------------------------------- /Source/swiftlint-dev/SwiftLintDev.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Foundation 3 | 4 | @main 5 | struct SwiftLintDev: AsyncParsableCommand { 6 | static let configuration = CommandConfiguration( 7 | commandName: "swiftlint-dev", 8 | abstract: "A tool to help develop SwiftLint.", 9 | subcommands: [ 10 | Reporters.self, 11 | Rules.self, 12 | ] 13 | ) 14 | 15 | struct Reporters: AsyncParsableCommand { 16 | static let configuration = CommandConfiguration( 17 | commandName: "reporters", 18 | abstract: "Manage SwiftLint reporters.", 19 | subcommands: [ 20 | Self.Register.self, 21 | ] 22 | ) 23 | } 24 | 25 | struct Rules: AsyncParsableCommand { 26 | static let configuration = CommandConfiguration( 27 | commandName: "rules", 28 | abstract: "Manage SwiftLint rules.", 29 | subcommands: [ 30 | Self.Register.self, 31 | Self.Template.self, 32 | ] 33 | ) 34 | } 35 | } 36 | 37 | extension URL { 38 | var relativeToCurrentDirectory: String { 39 | String(path.replacingOccurrences(of: FileManager.default.currentDirectoryPath, with: "").dropFirst()) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/swiftlint/Commands/GenerateDocs.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Foundation 3 | import SwiftLintFramework 4 | 5 | extension SwiftLint { 6 | struct GenerateDocs: ParsableCommand { 7 | static let configuration = CommandConfiguration( 8 | abstract: "Generates markdown documentation for selected group of rules" 9 | ) 10 | 11 | @Option(help: "The directory where the documentation should be saved") 12 | var path = "rule_docs" 13 | @Option(help: "The path to a SwiftLint configuration file") 14 | var config: String? 15 | @OptionGroup 16 | var rulesFilterOptions: RulesFilterOptions 17 | 18 | func run() throws { 19 | let configuration = Configuration(configurationFiles: [config].compactMap({ $0 })) 20 | let rulesFilter = RulesFilter(enabledRules: configuration.rules) 21 | let rules = rulesFilter.getRules(excluding: rulesFilterOptions.excludingOptions) 22 | 23 | try RuleListDocumentation(rules) 24 | .write(to: URL(fileURLWithPath: path, isDirectory: true)) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/swiftlint/Commands/Reporters.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import SwiftLintFramework 3 | import SwiftyTextTable 4 | 5 | extension SwiftLint { 6 | struct Reporters: ParsableCommand { 7 | static let configuration = CommandConfiguration(abstract: "Display the list of reporters and their identifiers") 8 | 9 | func run() throws { 10 | print(TextTable(reporters: reportersList).render()) 11 | } 12 | } 13 | } 14 | 15 | // MARK: - SwiftyTextTable 16 | 17 | private extension TextTable { 18 | init(reporters: [any Reporter.Type]) { 19 | let columns = [ 20 | TextTableColumn(header: "identifier"), 21 | TextTableColumn(header: "description"), 22 | ] 23 | self.init(columns: columns) 24 | for reporter in reporters { 25 | addRow(values: [ 26 | reporter.identifier, 27 | reporter.description, 28 | ]) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Source/swiftlint/Commands/SwiftLint.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import Foundation 3 | import SwiftLintFramework 4 | 5 | #if swift(<5.9) 6 | #error("SwiftLint requires Swift 5.9 or later to build") 7 | #endif 8 | 9 | @main 10 | struct SwiftLint: AsyncParsableCommand { 11 | static let configuration: CommandConfiguration = { 12 | if let directory = ProcessInfo.processInfo.environment["BUILD_WORKSPACE_DIRECTORY"] { 13 | if !FileManager.default.changeCurrentDirectoryPath(directory) { 14 | queuedFatalError(""" 15 | Could not change current directory to \(directory) specified by BUILD_WORKSPACE_DIRECTORY. 16 | """) 17 | } 18 | } 19 | 20 | RuleRegistry.registerAllRulesOnce() 21 | 22 | return CommandConfiguration( 23 | commandName: "swiftlint", 24 | abstract: "A tool to enforce Swift style and conventions.", 25 | version: Version.value, 26 | subcommands: [ 27 | Analyze.self, 28 | Docs.self, 29 | GenerateDocs.self, 30 | Lint.self, 31 | Baseline.self, 32 | Reporters.self, 33 | Rules.self, 34 | Version.self, 35 | ], 36 | defaultSubcommand: Lint.self 37 | ) 38 | }() 39 | } 40 | -------------------------------------------------------------------------------- /Source/swiftlint/Commands/Version.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import SwiftLintFramework 3 | 4 | extension SwiftLint { 5 | struct Version: AsyncParsableCommand { 6 | @Flag(help: "Display full version info.") 7 | var verbose = false 8 | @Flag(help: "Check whether a later version of SwiftLint is available after processing all files.") 9 | var checkForUpdates = false 10 | 11 | static let configuration = CommandConfiguration(abstract: "Display the current version of SwiftLint") 12 | 13 | static var value: String { SwiftLintFramework.Version.current.value } 14 | 15 | func run() async { 16 | if verbose, let buildID = ExecutableInfo.buildID { 17 | print("Version:", Self.value) 18 | print("Build ID:", buildID) 19 | } else { 20 | print(Self.value) 21 | } 22 | if checkForUpdates { 23 | await UpdateChecker.checkForUpdates() 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/swiftlint/Common/RulesFilterOptions.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import SwiftLintFramework 3 | 4 | enum RuleEnablementOptions: String, EnumerableFlag { 5 | case enabled, disabled 6 | 7 | static func name(for _: Self) -> NameSpecification { 8 | .shortAndLong 9 | } 10 | 11 | static func help(for value: Self) -> ArgumentHelp? { 12 | "Only show \(value.rawValue) rules" 13 | } 14 | } 15 | 16 | struct RulesFilterOptions: ParsableArguments { 17 | @Flag(exclusivity: .exclusive) 18 | var ruleEnablement: RuleEnablementOptions? 19 | @Flag(name: .shortAndLong, help: "Only display correctable rules") 20 | var correctable = false 21 | 22 | var excludingOptions: RulesFilter.ExcludingOptions { 23 | var excludingOptions: RulesFilter.ExcludingOptions = [] 24 | 25 | switch ruleEnablement { 26 | case .enabled: 27 | excludingOptions.insert(.disabled) 28 | case .disabled: 29 | excludingOptions.insert(.enabled) 30 | case .none: 31 | break 32 | } 33 | 34 | if correctable { 35 | excludingOptions.insert(.uncorrectable) 36 | } 37 | 38 | return excludingOptions 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /SwiftLint.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'SwiftLint' 3 | s.version = '0.59.1' 4 | s.summary = 'A tool to enforce Swift style and conventions.' 5 | s.homepage = 'https://github.com/realm/SwiftLint' 6 | s.license = { type: 'MIT', file: 'LICENSE' } 7 | s.author = { 'JP Simard' => 'jp@jpsim.com' } 8 | s.source = { http: "#{s.homepage}/releases/download/#{s.version}/portable_swiftlint.zip" } 9 | s.preserve_paths = '*' 10 | s.exclude_files = '**/file.zip' 11 | s.ios.deployment_target = '11.0' 12 | s.macos.deployment_target = '10.13' 13 | s.tvos.deployment_target = '11.0' 14 | s.watchos.deployment_target = '7.0' 15 | end 16 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/ChildOptionSeverityConfigurationTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | import XCTest 4 | 5 | final class ChildOptionSeverityConfigurationTests: SwiftLintTestCase { 6 | typealias TesteeType = ChildOptionSeverityConfiguration<RuleMock> 7 | 8 | func testSeverity() { 9 | XCTAssertNil(TesteeType.off.severity) 10 | XCTAssertEqual(TesteeType.warning.severity, .warning) 11 | XCTAssertEqual(TesteeType.error.severity, .error) 12 | } 13 | 14 | func testFromConfig() throws { 15 | var testee = TesteeType.off 16 | 17 | try testee.apply(configuration: "warning") 18 | XCTAssertEqual(testee, .warning) 19 | 20 | try testee.apply(configuration: "error") 21 | XCTAssertEqual(testee, .error) 22 | 23 | try testee.apply(configuration: "off") 24 | XCTAssertEqual(testee, .off) 25 | } 26 | 27 | func testInvalidConfig() { 28 | var testee = TesteeType.off 29 | 30 | XCTAssertThrowsError(try testee.apply(configuration: "no")) 31 | XCTAssertThrowsError(try testee.apply(configuration: 1)) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/CollectionAlignmentRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | 4 | final class CollectionAlignmentRuleTests: SwiftLintTestCase { 5 | func testCollectionAlignmentWithAlignLeft() { 6 | let baseDescription = CollectionAlignmentRule.description 7 | let examples = CollectionAlignmentRule.Examples(alignColons: false) 8 | 9 | let description = baseDescription.with(nonTriggeringExamples: examples.nonTriggeringExamples, 10 | triggeringExamples: examples.triggeringExamples) 11 | 12 | verifyRule(description) 13 | } 14 | 15 | func testCollectionAlignmentWithAlignColons() { 16 | let baseDescription = CollectionAlignmentRule.description 17 | let examples = CollectionAlignmentRule.Examples(alignColons: true) 18 | 19 | let description = baseDescription.with(nonTriggeringExamples: examples.nonTriggeringExamples, 20 | triggeringExamples: examples.triggeringExamples) 21 | 22 | verifyRule(description, ruleConfiguration: ["align_colons": true]) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/CompilerProtocolInitRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | import XCTest 4 | 5 | final class CompilerProtocolInitRuleTests: SwiftLintTestCase { 6 | private let ruleID = CompilerProtocolInitRule.identifier 7 | 8 | func testViolationMessageForExpressibleByIntegerLiteral() throws { 9 | let config = try XCTUnwrap(makeConfig(nil, ruleID)) 10 | let allViolations = violations(Example("let a = NSNumber(integerLiteral: 1)"), config: config) 11 | 12 | let compilerProtocolInitViolation = allViolations.first { $0.ruleIdentifier == ruleID } 13 | let violation = try XCTUnwrap( 14 | compilerProtocolInitViolation, 15 | "A compiler protocol init violation should have been triggered!" 16 | ) 17 | XCTAssertEqual( 18 | violation.reason, 19 | "Initializers declared in compiler protocol ExpressibleByIntegerLiteral shouldn't be called directly" 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/ConditionalReturnsOnNewlineRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | 4 | final class ConditionalReturnsOnNewlineRuleTests: SwiftLintTestCase { 5 | func testConditionalReturnsOnNewlineWithIfOnly() { 6 | // Test with `if_only` set to true 7 | let nonTriggeringExamples = [ 8 | Example("guard true else {\n return true\n}"), 9 | Example("guard true,\n let x = true else {\n return true\n}"), 10 | Example("if true else {\n return true\n}"), 11 | Example("if true,\n let x = true else {\n return true\n}"), 12 | Example("if textField.returnKeyType == .Next {"), 13 | Example("if true { // return }"), 14 | Example("/*if true { */ return }"), 15 | Example("guard true else { return }"), 16 | ] 17 | let triggeringExamples = [ 18 | Example("↓if true { return }"), 19 | Example("↓if true { break } else { return }"), 20 | Example("↓if true { break } else { return }"), 21 | Example("↓if true { return \"YES\" } else { return \"NO\" }"), 22 | ] 23 | 24 | let description = ConditionalReturnsOnNewlineRule.description 25 | .with(triggeringExamples: triggeringExamples) 26 | .with(nonTriggeringExamples: nonTriggeringExamples) 27 | 28 | verifyRule(description, ruleConfiguration: ["if_only": true]) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/ContainsOverFirstNotNilRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | import XCTest 4 | 5 | final class ContainsOverFirstNotNilRuleTests: SwiftLintTestCase { 6 | func testFirstReason() { 7 | let example = Example("↓myList.first { $0 % 2 == 0 } != nil") 8 | let violations = self.violations(example) 9 | 10 | XCTAssertEqual(violations.count, 1) 11 | XCTAssertEqual(violations.first?.reason, "Prefer `contains` over `first(where:) != nil`") 12 | } 13 | 14 | func testFirstIndexReason() { 15 | let example = Example("↓myList.firstIndex { $0 % 2 == 0 } != nil") 16 | let violations = self.violations(example) 17 | 18 | XCTAssertEqual(violations.count, 1) 19 | XCTAssertEqual(violations.first?.reason, "Prefer `contains` over `firstIndex(where:) != nil`") 20 | } 21 | 22 | // MARK: - Private 23 | 24 | private func violations(_ example: Example, config: Any? = nil) -> [StyleViolation] { 25 | guard let config = makeConfig(config, ContainsOverFirstNotNilRule.identifier) else { 26 | return [] 27 | } 28 | 29 | return TestHelpers.violations(example, config: config) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/DuplicateImportsRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import XCTest 3 | 4 | final class DuplicateImportsRuleTests: XCTestCase { 5 | func testDisableCommand() { 6 | let content = """ 7 | import InspireAPI 8 | // swiftlint:disable:next duplicate_imports 9 | import class InspireAPI.Response 10 | """ 11 | let file = SwiftLintFile(contents: content) 12 | 13 | _ = DuplicateImportsRule().correct(file: file) 14 | 15 | XCTAssertEqual(file.contents, content) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/ExplicitInitRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | 4 | final class ExplicitInitRuleTests: SwiftLintTestCase { 5 | func testIncludeBareInit() { 6 | let nonTriggeringExamples = [ 7 | Example("let foo = Foo()"), 8 | Example("let foo = init()"), 9 | ] + ExplicitInitRule.description.nonTriggeringExamples 10 | 11 | let triggeringExamples = [ 12 | Example("let foo: Foo = ↓.init()"), 13 | Example("let foo: [Foo] = [↓.init(), ↓.init()]"), 14 | Example("foo(↓.init())"), 15 | ] 16 | 17 | let description = ExplicitInitRule.description 18 | .with(nonTriggeringExamples: nonTriggeringExamples) 19 | .with(triggeringExamples: triggeringExamples) 20 | 21 | verifyRule(description, ruleConfiguration: ["include_bare_init": true]) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/FileLengthRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | 4 | final class FileLengthRuleTests: SwiftLintTestCase { 5 | func testFileLengthWithDefaultConfiguration() { 6 | verifyRule(FileLengthRule.description, commentDoesntViolate: false, 7 | testMultiByteOffsets: false, testShebang: false) 8 | } 9 | 10 | func testFileLengthIgnoringLinesWithOnlyComments() { 11 | let triggeringExamples = [ 12 | Example(repeatElement("print(\"swiftlint\")\n", count: 401).joined()) 13 | ] 14 | let nonTriggeringExamples = [ 15 | Example((repeatElement("print(\"swiftlint\")\n", count: 400) + ["//\n"]).joined()), 16 | Example(repeatElement("print(\"swiftlint\")\n", count: 400).joined()), 17 | Example(repeatElement("print(\"swiftlint\")\n\n", count: 201).joined()), 18 | ] 19 | 20 | let description = FileLengthRule.description 21 | .with(nonTriggeringExamples: nonTriggeringExamples) 22 | .with(triggeringExamples: triggeringExamples) 23 | 24 | verifyRule(description, ruleConfiguration: ["ignore_comment_only_lines": true], 25 | testMultiByteOffsets: false, testShebang: false) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/ImplicitGetterRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | import XCTest 4 | 5 | final class ImplicitGetterRuleTests: SwiftLintTestCase { 6 | func testPropertyReason() throws { 7 | let config = try XCTUnwrap(makeConfig(nil, ImplicitGetterRule.identifier)) 8 | let example = Example(""" 9 | class Foo { 10 | var foo: Int { 11 | ↓get { 12 | return 20 13 | } 14 | } 15 | } 16 | """) 17 | 18 | let violations = violations(example, config: config) 19 | XCTAssertEqual(violations.count, 1) 20 | XCTAssertEqual(violations.first?.reason, "Computed read-only properties should avoid using the get keyword") 21 | } 22 | 23 | func testSubscriptReason() throws { 24 | let config = try XCTUnwrap(makeConfig(nil, ImplicitGetterRule.identifier)) 25 | let example = Example(""" 26 | class Foo { 27 | subscript(i: Int) -> Int { 28 | ↓get { 29 | return 20 30 | } 31 | } 32 | } 33 | """) 34 | 35 | let violations = violations(example, config: config) 36 | XCTAssertEqual(violations.count, 1) 37 | XCTAssertEqual(violations.first?.reason, "Computed read-only subscripts should avoid using the get keyword") 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/InclusiveLanguageRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | 4 | final class InclusiveLanguageRuleTests: SwiftLintTestCase { 5 | func testNonTriggeringExamplesWithNonDefaultConfig() { 6 | InclusiveLanguageRuleExamples.nonTriggeringExamplesWithConfig.forEach { example in 7 | let description = InclusiveLanguageRule.description 8 | .with(nonTriggeringExamples: [example]) 9 | .with(triggeringExamples: []) 10 | verifyRule(description, ruleConfiguration: example.configuration) 11 | } 12 | } 13 | 14 | func testTriggeringExamplesWithNonDefaultConfig() { 15 | InclusiveLanguageRuleExamples.triggeringExamplesWithConfig.forEach { example in 16 | let description = InclusiveLanguageRule.description 17 | .with(nonTriggeringExamples: []) 18 | .with(triggeringExamples: [example]) 19 | verifyRule(description, ruleConfiguration: example.configuration) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/PreferKeyPathRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | import XCTest 4 | 5 | final class PreferKeyPathRuleTests: SwiftLintTestCase { 6 | private static let extendedMode = ["restrict_to_standard_functions": false] 7 | 8 | func testIdentityExpressionInSwift6() throws { 9 | try XCTSkipIf(SwiftVersion.current < .six) 10 | 11 | let description = PreferKeyPathRule.description 12 | .with(nonTriggeringExamples: [ 13 | Example("f.filter { a in b }"), 14 | Example("f.g { $1 }", configuration: Self.extendedMode), 15 | ]) 16 | .with(triggeringExamples: [ 17 | Example("f.compactMap ↓{ $0 }"), 18 | Example("f.map ↓{ a in a }"), 19 | Example("f.g { $0 }", configuration: Self.extendedMode), 20 | ]) 21 | .with(corrections: [ 22 | Example("f.map ↓{ $0 }"): 23 | Example("f.map(\\.self)"), 24 | Example("f.g { $0 }", configuration: Self.extendedMode): 25 | Example("f.g(\\.self)"), 26 | ]) 27 | 28 | verifyRule(description) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/PrefixedTopLevelConstantRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | 4 | final class PrefixedTopLevelConstantRuleTests: SwiftLintTestCase { 5 | func testPrivateOnly() { 6 | let triggeringExamples = [ 7 | Example("private let ↓Foo = 20.0"), 8 | Example("fileprivate let ↓foo = 20.0"), 9 | ] 10 | let nonTriggeringExamples = [ 11 | Example("let Foo = 20.0"), 12 | Example("internal let Foo = \"Foo\""), 13 | Example("public let Foo = 20.0"), 14 | ] 15 | 16 | let description = PrefixedTopLevelConstantRule.description 17 | .with(triggeringExamples: triggeringExamples) 18 | .with(nonTriggeringExamples: nonTriggeringExamples) 19 | 20 | verifyRule(description, ruleConfiguration: ["only_private": true]) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileHeaderRuleFixtures/DocumentedType.swift: -------------------------------------------------------------------------------- 1 | /// This is the documentation for struct A. 2 | struct A {} 3 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileHeaderRuleFixtures/FileHeaderEmpty.swift: -------------------------------------------------------------------------------- 1 | struct A {} 2 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileHeaderRuleFixtures/FileNameCaseMismatch.swift: -------------------------------------------------------------------------------- 1 | // FileNameCaseMismatch.Swift 2 | // Copyright © 2016 3 | struct A {} 4 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileHeaderRuleFixtures/FileNameMatchingComplex.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 2 | // File: "FileNameMatchingComplex.swift" 3 | struct A {} 4 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileHeaderRuleFixtures/FileNameMatchingSimple.swift: -------------------------------------------------------------------------------- 1 | // FileNameMatchingSimple.swift 2 | // Copyright © 2016 3 | struct A {} 4 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileHeaderRuleFixtures/FileNameMismatch.swift: -------------------------------------------------------------------------------- 1 | // AFileNameMismatch.swift 2 | // Copyright © 2016 3 | struct A {} 4 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileHeaderRuleFixtures/FileNameMissing.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016 3 | struct A {} 4 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameNoSpaceRuleFixtures/File Name.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realm/SwiftLint/c1ffdfe8913c12398a3a05fe19844c1031fa7add/Tests/BuiltInRulesTests/Resources/FileNameNoSpaceRuleFixtures/File Name.swift -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameNoSpaceRuleFixtures/File+Extension.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realm/SwiftLint/c1ffdfe8913c12398a3a05fe19844c1031fa7add/Tests/BuiltInRulesTests/Resources/FileNameNoSpaceRuleFixtures/File+Extension.swift -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameNoSpaceRuleFixtures/File+Test Extension.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realm/SwiftLint/c1ffdfe8913c12398a3a05fe19844c1031fa7add/Tests/BuiltInRulesTests/Resources/FileNameNoSpaceRuleFixtures/File+Test Extension.swift -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameNoSpaceRuleFixtures/File.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realm/SwiftLint/c1ffdfe8913c12398a3a05fe19844c1031fa7add/Tests/BuiltInRulesTests/Resources/FileNameNoSpaceRuleFixtures/File.swift -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/BoolExtension.swift: -------------------------------------------------------------------------------- 1 | struct MyStruct {} 2 | class MyClass {} 3 | 4 | extension Bool { 5 | func toggle() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/BoolExtensionTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SomeModule 2 | import XCTest 3 | 4 | final class BoolExtensionTests: SwiftLintTestCase { 5 | func testExample() { 6 | // some code 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/BoolExtensions.swift: -------------------------------------------------------------------------------- 1 | struct MyStruct {} 2 | class MyClass {} 3 | 4 | extension Bool { 5 | func toggle() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/ExtensionBool+SwiftLint.swift: -------------------------------------------------------------------------------- 1 | struct MyStruct {} 2 | class MyClass {} 3 | 4 | extension Bool { 5 | func toggle() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/ExtensionBool.swift: -------------------------------------------------------------------------------- 1 | struct MyStruct {} 2 | class MyClass {} 3 | 4 | extension Bool { 5 | func toggle() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/ExtensionsBool.swift: -------------------------------------------------------------------------------- 1 | struct MyStruct {} 2 | class MyClass {} 3 | 4 | extension Bool { 5 | func toggle() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRulesTests 2 | import XCTest 3 | 4 | extension AttributesRuleTests { 5 | static var allTests: [(String, (AttributesRuleTests) -> () throws -> Void)] = [ 6 | ("testAttributesWithDefaultConfiguration", testAttributesWithDefaultConfiguration), 7 | ("testAttributesWithAlwaysOnSameLine", testAttributesWithAlwaysOnSameLine), 8 | ("testAttributesWithAlwaysOnLineAbove", testAttributesWithAlwaysOnLineAbove), 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/Multiple.Levels.Deeply.Nested.MyType.swift: -------------------------------------------------------------------------------- 1 | extension Multiple { 2 | enum Levels { 3 | class Deeply { 4 | struct Nested { 5 | actor MyType {} 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/MyClass.swift: -------------------------------------------------------------------------------- 1 | struct MyStruct {} 2 | class MyClass {} 3 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/MyMacro.swift: -------------------------------------------------------------------------------- 1 | macro MyMacro = #externalMacro( 2 | module: "Module", 3 | type: "Type" 4 | ) 5 | struct MyStruct {} 6 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/MyStruct.swift: -------------------------------------------------------------------------------- 1 | struct MyStruct {} 2 | class MyClass {} 3 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/MyStructf.swift: -------------------------------------------------------------------------------- 1 | struct MyStruct {} 2 | class MyClass {} 3 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/MyType.swift: -------------------------------------------------------------------------------- 1 | enum Nested { 2 | struct MyType {} 3 | } 4 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/NSString+Extension.swift: -------------------------------------------------------------------------------- 1 | struct MyStruct {} 2 | class MyClass {} 3 | 4 | extension NSString { 5 | func asdf() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/Nested.MyType.swift: -------------------------------------------------------------------------------- 1 | enum Nested { 2 | struct MyType { 3 | } 4 | } 5 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/Notification.Name+Extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Notification.Name { 4 | } 5 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/NotificationName+Extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Notification.Name { 4 | } 5 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/Notification__Name+Extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Notification.Name { 4 | } 5 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/SLBoolExtension.swift: -------------------------------------------------------------------------------- 1 | struct MyStruct {} 2 | class MyClass {} 3 | 4 | extension Bool { 5 | func toggle() {} 6 | } 7 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/Resources/FileNameRuleFixtures/main.swift: -------------------------------------------------------------------------------- 1 | struct A {} 2 | 3 | print("hello") 4 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/StatementPositionRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | 4 | final class StatementPositionRuleTests: SwiftLintTestCase { 5 | func testStatementPositionUncuddled() { 6 | let configuration = ["statement_mode": "uncuddled_else"] 7 | verifyRule(StatementPositionRule.uncuddledDescription, ruleConfiguration: configuration) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/SwitchCaseAlignmentRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | 4 | final class SwitchCaseAlignmentRuleTests: SwiftLintTestCase { 5 | func testSwitchCaseAlignmentWithoutIndentedCases() { 6 | let baseDescription = SwitchCaseAlignmentRule.description 7 | let examples = SwitchCaseAlignmentRule.Examples(indentedCases: false) 8 | 9 | let description = baseDescription.with(nonTriggeringExamples: examples.nonTriggeringExamples, 10 | triggeringExamples: examples.triggeringExamples) 11 | 12 | verifyRule(description) 13 | } 14 | 15 | func testSwitchCaseAlignmentWithIndentedCases() { 16 | let baseDescription = SwitchCaseAlignmentRule.description 17 | let examples = SwitchCaseAlignmentRule.Examples(indentedCases: true) 18 | 19 | let description = baseDescription.with(nonTriggeringExamples: examples.nonTriggeringExamples, 20 | triggeringExamples: examples.triggeringExamples) 21 | 22 | verifyRule(description, ruleConfiguration: ["indented_cases": true]) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/TrailingClosureConfigurationTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | import XCTest 4 | 5 | final class TrailingClosureConfigurationTests: SwiftLintTestCase { 6 | func testDefaultConfiguration() { 7 | let config = TrailingClosureConfiguration() 8 | XCTAssertEqual(config.severityConfiguration.severity, .warning) 9 | XCTAssertFalse(config.onlySingleMutedParameter) 10 | } 11 | 12 | func testApplyingCustomConfiguration() throws { 13 | var config = TrailingClosureConfiguration() 14 | try config.apply( 15 | configuration: [ 16 | "severity": "error", 17 | "only_single_muted_parameter": true, 18 | ] as [String: any Sendable] 19 | ) 20 | XCTAssertEqual(config.severityConfiguration.severity, .error) 21 | XCTAssertTrue(config.onlySingleMutedParameter) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/TrailingClosureRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | 4 | final class TrailingClosureRuleTests: SwiftLintTestCase { 5 | func testWithOnlySingleMutedParameterEnabled() { 6 | let originalDescription = TrailingClosureRule.description 7 | let description = originalDescription 8 | .with(nonTriggeringExamples: originalDescription.nonTriggeringExamples + [ 9 | Example("foo.reduce(0, combine: { $0 + 1 })"), 10 | Example("offsets.sorted(by: { $0.offset < $1.offset })"), 11 | Example("foo.something(0, { $0 + 1 })"), 12 | ]) 13 | .with(triggeringExamples: [Example("foo.map(↓{ $0 + 1 })")]) 14 | .with(corrections: [ 15 | Example("foo.map(↓{ $0 + 1 })"): 16 | Example("foo.map { $0 + 1 }"), 17 | Example("f(↓{ g(↓{ 1 }) })"): 18 | Example("f { g { 1 }}"), 19 | Example(""" 20 | for n in list { 21 | n.forEach(↓{ print($0) }) 22 | } 23 | """): Example(""" 24 | for n in list { 25 | n.forEach { print($0) } 26 | } 27 | """), 28 | ]) 29 | 30 | verifyRule(description, ruleConfiguration: ["only_single_muted_parameter": true]) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/TypesafeArrayInitRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | import XCTest 4 | 5 | final class TypesafeArrayInitRuleTests: SwiftLintTestCase { 6 | func testViolationRuleIdentifier() { 7 | let baseDescription = TypesafeArrayInitRule.description 8 | guard let triggeringExample = baseDescription.triggeringExamples.first else { 9 | XCTFail("No triggering examples found") 10 | return 11 | } 12 | guard let config = makeConfig(nil, baseDescription.identifier) else { 13 | XCTFail("Failed to create configuration") 14 | return 15 | } 16 | let violations = violations(triggeringExample, config: config, requiresFileOnDisk: true) 17 | XCTAssertGreaterThanOrEqual(violations.count, 1) 18 | XCTAssertEqual(violations.first?.ruleIdentifier, baseDescription.identifier) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/UnusedDeclarationConfigurationTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import XCTest 3 | 4 | final class UnusedDeclarationConfigurationTests: XCTestCase { 5 | func testParseConfiguration() throws { 6 | var testee = UnusedDeclarationConfiguration() 7 | let config = [ 8 | "severity": "warning", 9 | "include_public_and_open": true, 10 | "related_usrs_to_skip": ["a", "b"], 11 | ] as [String: any Sendable] 12 | 13 | try testee.apply(configuration: config) 14 | 15 | XCTAssertEqual(testee.severityConfiguration.severity, .warning) 16 | XCTAssertTrue(testee.includePublicAndOpen) 17 | XCTAssertEqual(testee.relatedUSRsToSkip, ["a", "b", "s:7SwiftUI15PreviewProviderP"]) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/BuiltInRulesTests/UnusedOptionalBindingRuleTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import TestHelpers 3 | 4 | final class UnusedOptionalBindingRuleTests: SwiftLintTestCase { 5 | func testDefaultConfiguration() { 6 | let baseDescription = UnusedOptionalBindingRule.description 7 | let triggeringExamples = baseDescription.triggeringExamples + [ 8 | Example("guard let _ = try? alwaysThrows() else { return }") 9 | ] 10 | 11 | let description = baseDescription.with(triggeringExamples: triggeringExamples) 12 | verifyRule(description) 13 | } 14 | 15 | func testIgnoreOptionalTryEnabled() { 16 | // Perform additional tests with the ignore_optional_try settings enabled. 17 | let baseDescription = UnusedOptionalBindingRule.description 18 | let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [ 19 | Example("guard let _ = try? alwaysThrows() else { return }") 20 | ] 21 | 22 | let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) 23 | verifyRule(description, ruleConfiguration: ["ignore_optional_try": true]) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/ExtraRulesTests/ExtraRulesTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintExtraRules 2 | import TestHelpers 3 | 4 | final class ExtraRulesTests: SwiftLintTestCase, @unchecked Sendable { 5 | func testWithDefaultConfiguration() { 6 | for ruleType in extraRules() { 7 | verifyRule(ruleType.description) 8 | } 9 | } 10 | } 11 | 12 | extension ExtraRulesTests { 13 | static var allTests: [(String, (ExtraRulesTests) -> () throws -> Void)] { 14 | [("testWithDefaultConfiguration", testWithDefaultConfiguration)] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/AccessControlLevelTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | import XCTest 3 | 4 | final class AccessControlLevelTests: SwiftLintTestCase { 5 | func testDescription() { 6 | XCTAssertEqual(AccessControlLevel.private.description, "private") 7 | XCTAssertEqual(AccessControlLevel.fileprivate.description, "fileprivate") 8 | XCTAssertEqual(AccessControlLevel.internal.description, "internal") 9 | XCTAssertEqual(AccessControlLevel.package.description, "package") 10 | XCTAssertEqual(AccessControlLevel.public.description, "public") 11 | XCTAssertEqual(AccessControlLevel.open.description, "open") 12 | } 13 | 14 | func testPriority() { 15 | XCTAssertLessThan(AccessControlLevel.private, .fileprivate) 16 | XCTAssertLessThan(AccessControlLevel.fileprivate, .internal) 17 | XCTAssertLessThan(AccessControlLevel.internal, .package) 18 | XCTAssertLessThan(AccessControlLevel.package, .public) 19 | XCTAssertLessThan(AccessControlLevel.public, .open) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Exports.swift: -------------------------------------------------------------------------------- 1 | // These imports are re-exported to make them available implicitly to all files. 2 | // swiftlint:disable:next unused_import 3 | @_exported import TestHelpers 4 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/ExtendedNSStringTests.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | import XCTest 3 | 4 | final class ExtendedNSStringTests: SwiftLintTestCase { 5 | func testLineAndCharacterForByteOffset_forContentsContainingMultibyteCharacters() { 6 | let contents = "" + 7 | "import Foundation\n" + // 18 characters 8 | "class Test {\n" + // 13 characters 9 | "func test() {\n" + // 14 characters 10 | "// 日本語コメント : comment in Japanese\n" + // 33 characters 11 | "// do something\n" + // 16 characters 12 | "}\n" + 13 | "}" 14 | // A character placed on 80 offset indicates a white-space before 'do' at 5th line. 15 | if let lineAndCharacter = StringView(contents).lineAndCharacter(forCharacterOffset: 80) { 16 | XCTAssertEqual(lineAndCharacter.line, 5) 17 | XCTAssertEqual(lineAndCharacter.character, 3) 18 | } else { 19 | XCTFail("NSString.lineAndCharacterForByteOffset should return non-nil tuple.") 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/ExtendedStringTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | final class ExtendedStringTests: SwiftLintTestCase { 4 | func testCountOccurrences() { 5 | XCTAssertEqual("aabbabaaba".countOccurrences(of: "a"), 6) 6 | XCTAssertEqual("".countOccurrences(of: "a"), 0) 7 | XCTAssertEqual("\n\n".countOccurrences(of: "\n"), 2) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/LineEndingTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | import XCTest 3 | 4 | final class LineEndingTests: SwiftLintTestCase { 5 | func testCarriageReturnDoesNotCauseError() { 6 | XCTAssert( 7 | violations( 8 | Example( 9 | "// swiftlint:disable:next blanket_disable_command\r\n" + 10 | "// swiftlint:disable all\r\nprint(123)\r\n" 11 | ) 12 | ).isEmpty 13 | ) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedCSVReporterOutput.csv: -------------------------------------------------------------------------------- 1 | file,line,character,severity,type,reason,rule_id 2 | filename,1,1,Warning,Line Length,Violation Reason 1,line_length 3 | filename,1,,Error,Line Length,Violation Reason 2,line_length 4 | ${CURRENT_WORKING_DIRECTORY}/path/file.swift,1,2,Error,Syntactic Sugar,"Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int>",syntactic_sugar 5 | ,,,Error,Colon Spacing,Colons should be next to the identifier when specifying a type and next to the key in dictionary literals,colon -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedCheckstyleReporterOutput.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <checkstyle version="4.3"> 3 | <file name="<nopath>"> 4 | <error line="0" column="0" severity="error" message="Colons should be next to the identifier when specifying a type and next to the key in dictionary literals" source="swiftlint.rules.colon"/> 5 | </file> 6 | <file name="${CURRENT_WORKING_DIRECTORY}/path/file.swift"> 7 | <error line="1" column="2" severity="error" message="Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int>" source="swiftlint.rules.syntactic_sugar"/> 8 | </file> 9 | <file name="filename"> 10 | <error line="1" column="1" severity="warning" message="Violation Reason 1" source="swiftlint.rules.line_length"/> 11 | <error line="1" column="0" severity="error" message="Violation Reason 2" source="swiftlint.rules.line_length"/> 12 | </file> 13 | </checkstyle> -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedEmojiReporterOutput.txt: -------------------------------------------------------------------------------- 1 | ${CURRENT_WORKING_DIRECTORY}/path/file.swift 2 | ⛔️ Line 1: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int> (syntactic_sugar) 3 | Other 4 | ⛔️ Colons should be next to the identifier when specifying a type and next to the key in dictionary literals (colon) 5 | filename 6 | ⛔️ Line 1: Violation Reason 2 (line_length) 7 | ⚠️ Line 1: Violation Reason 1 (line_length) -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedGitHubActionsLoggingReporterOutput.txt: -------------------------------------------------------------------------------- 1 | ::warning file=filename,line=1,col=1::Violation Reason 1 (line_length) 2 | ::error file=filename,line=1,col=1::Violation Reason 2 (line_length) 3 | ::error file=path/file.swift,line=1,col=2::Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int> (syntactic_sugar) 4 | ::error file=,line=1,col=1::Colons should be next to the identifier when specifying a type and next to the key in dictionary literals (colon) -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedGitLabJUnitReporterOutput.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <testsuites><testsuite> 3 | <testcase name='warning: line_length in filename:1'> 4 | <failure>Severity: warning 5 | Rule: line_length 6 | Reason: Violation Reason 1 7 | 8 | File: filename 9 | Line: 1 10 | Column: 1 11 | </failure> 12 | </testcase> 13 | <testcase name='error: line_length in filename:1'> 14 | <failure>Severity: error 15 | Rule: line_length 16 | Reason: Violation Reason 2 17 | 18 | File: filename 19 | Line: 1 20 | Column: nil 21 | </failure> 22 | </testcase> 23 | <testcase name='error: syntactic_sugar in path/file.swift:1'> 24 | <failure>Severity: error 25 | Rule: syntactic_sugar 26 | Reason: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int> 27 | 28 | File: path/file.swift 29 | Line: 1 30 | Column: 2 31 | </failure> 32 | </testcase> 33 | <testcase name='error: colon in <nopath>'> 34 | <failure>Severity: error 35 | Rule: colon 36 | Reason: Colons should be next to the identifier when specifying a type and next to the key in dictionary literals 37 | 38 | File: <nopath> 39 | Line: nil 40 | Column: nil 41 | </failure> 42 | </testcase> 43 | </testsuite></testsuites> 44 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedJSONReporterOutput.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "character" : 1, 4 | "file" : "filename", 5 | "line" : 1, 6 | "reason" : "Violation Reason 1", 7 | "rule_id" : "line_length", 8 | "severity" : "Warning", 9 | "type" : "Line Length" 10 | }, 11 | { 12 | "character" : null, 13 | "file" : "filename", 14 | "line" : 1, 15 | "reason" : "Violation Reason 2", 16 | "rule_id" : "line_length", 17 | "severity" : "Error", 18 | "type" : "Line Length" 19 | }, 20 | { 21 | "character" : 2, 22 | "file" : "${CURRENT_WORKING_DIRECTORY}/path/file.swift", 23 | "line" : 1, 24 | "reason" : "Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int>", 25 | "rule_id" : "syntactic_sugar", 26 | "severity" : "Error", 27 | "type" : "Syntactic Sugar" 28 | }, 29 | { 30 | "character" : null, 31 | "file" : null, 32 | "line" : null, 33 | "reason" : "Colons should be next to the identifier when specifying a type and next to the key in dictionary literals", 34 | "rule_id" : "colon", 35 | "severity" : "Error", 36 | "type" : "Colon Spacing" 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedJunitReporterOutput.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <testsuites failures="1" errors="3"> 3 | <testsuite failures="1" errors="3"> 4 | <testcase classname='Formatting Test' name='filename'> 5 | <failure message='Violation Reason 1'>Warning:Line:1</failure> 6 | </testcase> 7 | <testcase classname='Formatting Test' name='filename'> 8 | <failure message='Violation Reason 2'>Error:Line:1</failure> 9 | </testcase> 10 | <testcase classname='Formatting Test' name='${CURRENT_WORKING_DIRECTORY}/path/file.swift'> 11 | <failure message='Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int>'>Error:Line:1</failure> 12 | </testcase> 13 | <testcase classname='Formatting Test' name='<nopath>'> 14 | <failure message='Colons should be next to the identifier when specifying a type and next to the key in dictionary literals'>Error:Line:0</failure> 15 | </testcase> 16 | </testsuite> 17 | </testsuites> -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedMarkdownReporterOutput.md: -------------------------------------------------------------------------------- 1 | file | line | severity | reason | rule_id 2 | --- | --- | --- | --- | --- 3 | filename | 1 | :warning: | Line Length: Violation Reason 1 | line_length 4 | filename | 1 | :stop\_sign: | Line Length: Violation Reason 2 | line_length 5 | ${CURRENT_WORKING_DIRECTORY}/path/file.swift | 1 | :stop\_sign: | Syntactic Sugar: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int> | syntactic_sugar 6 | | | :stop\_sign: | Colon Spacing: Colons should be next to the identifier when specifying a type and next to the key in dictionary literals | colon -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedRelativePathReporterOutput.txt: -------------------------------------------------------------------------------- 1 | filename:1:1: warning: Line Length Violation: Violation Reason 1 (line_length) 2 | filename:1:1: error: Line Length Violation: Violation Reason 2 (line_length) 3 | path/file.swift:1:2: error: Syntactic Sugar Violation: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int> (syntactic_sugar) 4 | <nopath>:1:1: error: Colon Spacing Violation: Colons should be next to the identifier when specifying a type and next to the key in dictionary literals (colon) -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedSummaryReporterNoViolationsOutput.txt: -------------------------------------------------------------------------------- 1 | +-----------------+--------+-------------+--------+----------+--------+------------------+-----------------+ 2 | | rule identifier | opt-in | correctable | custom | warnings | errors | total violations | number of files | 3 | +-----------------+--------+-------------+--------+----------+--------+------------------+-----------------+ 4 | | Total | | | | 0 | 0 | 0 | 0 | 5 | +-----------------+--------+-------------+--------+----------+--------+------------------+-----------------+ 6 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedSummaryReporterOutput.txt: -------------------------------------------------------------------------------- 1 | +------------------------------------+--------+-------------+--------+----------+--------+------------------+-----------------+ 2 | | rule identifier | opt-in | correctable | custom | warnings | errors | total violations | number of files | 3 | +------------------------------------+--------+-------------+--------+----------+--------+------------------+-----------------+ 4 | | line_length | no | no | no | 1 | 1 | 2 | 1 | 5 | | colon | no | yes | no | 0 | 1 | 1 | 1 | 6 | | syntactic_sugar | no | yes | no | 0 | 1 | 1 | 1 | 7 | | vertical_whitespace_opening_braces | yes | yes | no | 1 | 0 | 1 | 1 | 8 | +------------------------------------+--------+-------------+--------+----------+--------+------------------+-----------------+ 9 | | Total | | | | 2 | 3 | 5 | 3 | 10 | +------------------------------------+--------+-------------+--------+----------+--------+------------------+-----------------+ 11 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/CannedXcodeReporterOutput.txt: -------------------------------------------------------------------------------- 1 | filename:1:1: warning: Line Length Violation: Violation Reason 1 (line_length) 2 | filename:1:1: error: Line Length Violation: Violation Reason 2 (line_length) 3 | ${CURRENT_WORKING_DIRECTORY}/path/file.swift:1:2: error: Syntactic Sugar Violation: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int> (syntactic_sugar) 4 | <nopath>:1:1: error: Colon Spacing Violation: Colons should be next to the identifier when specifying a type and next to the key in dictionary literals (colon) -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - force_cast 3 | included: 4 | - "everything" 5 | excluded: 6 | - "the place where i committed many coding sins" 7 | line_length: 10000000000 8 | reporter: "json" 9 | allow_zero_lintable_files: true 10 | strict: true 11 | baseline: Baseline.json 12 | write_baseline: Baseline.json 13 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Cycle1/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | line_length: 60 2 | 3 | child_config: .swiftlint.yml 4 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Cycle2/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | line_length: 60 2 | 3 | child_config: child.yml 4 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Cycle2/child.yml: -------------------------------------------------------------------------------- 1 | child_config: .swiftlint.yml 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Cycle3/Main/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | line_length: 60 2 | 3 | child_config: child1.yml 4 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Cycle3/Main/Folder/child2.yml: -------------------------------------------------------------------------------- 1 | child_config: ../../child3.yml 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Cycle3/Main/child1.yml: -------------------------------------------------------------------------------- 1 | child_config: Folder/child2.yml 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Cycle3/child3.yml: -------------------------------------------------------------------------------- 1 | child_config: Main/.swiftlint.yml 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Cycle4/child.yml: -------------------------------------------------------------------------------- 1 | child_config: main.yml 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Cycle4/main.yml: -------------------------------------------------------------------------------- 1 | line_length: 60 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Test1/Main/Folder/child3.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - SomeFile 3 | 4 | child_config: ../../child4.yml 5 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Test1/Main/child1.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1/Test 3 | - Test/Test2/Test 4 | 5 | excluded: 6 | - Test/Test1/Test/Test 7 | - Test/Test2/Test/Test 8 | 9 | child_config: child2.yml 10 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Test1/Main/child2.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1/Test/Test 3 | - Test/Test2/Test/Test 4 | 5 | child_config: Folder/child3.yml 6 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Test1/Main/expected.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1 3 | - Test/Test2 4 | - Test/Test1/Test 5 | - Test/Test2/Test 6 | - Test/Test1/Test/Test 7 | - Test/Test2/Test/Test 8 | - Folder/SomeFile 9 | - ../SomeFile 10 | 11 | line_length: 80 12 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Test1/Main/main.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1 3 | - Test/Test2 4 | 5 | excluded: 6 | - Test/Test1/Test 7 | - Test/Test2/Test 8 | 9 | line_length: 80 10 | 11 | child_config: child1.yml 12 | parent_config: nonExistingParent.yml 13 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Test1/child4.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - SomeFile 3 | 4 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Test2/child1.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - private_outlet 3 | 4 | included: 5 | - Test/Test1/Test 6 | - Test/Test2/Test 7 | 8 | excluded: 9 | - Test/Test1/Test/Test 10 | - Test/Test2/Test/Test 11 | 12 | child_config: child2.yml 13 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Test2/child2.yml: -------------------------------------------------------------------------------- 1 | opt_in_rules: 2 | - identifier_name 3 | 4 | disabled_rules: 5 | - trailing_closure 6 | - empty_count 7 | 8 | line_length: 80 9 | 10 | identifier_name: 11 | excluded: 12 | - abc 13 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Test2/expected.yml: -------------------------------------------------------------------------------- 1 | opt_in_rules: 2 | - private_action 3 | 4 | disabled_rules: 5 | - empty_count 6 | - force_cast 7 | - private_outlet 8 | - trailing_closure 9 | 10 | line_length: 80 11 | 12 | identifier_name: 13 | excluded: 14 | - abc 15 | 16 | included: 17 | - Test/Test1 18 | - Test/Test2 19 | - Test/Test1/Test 20 | - Test/Test2/Test 21 | 22 | excluded: 23 | - Test/Test1/Test/Test 24 | - Test/Test2/Test/Test 25 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ChildConfig/Test2/main.yml: -------------------------------------------------------------------------------- 1 | opt_in_rules: 2 | - private_action 3 | - private_outlet 4 | - trailing_closure 5 | - empty_count 6 | 7 | disabled_rules: 8 | - force_cast 9 | - identifier_name 10 | 11 | line_length: 160 12 | 13 | included: 14 | - Test/Test1 15 | - Test/Test2 16 | 17 | excluded: 18 | - Test/Test1/Test 19 | - Test/Test2/Test 20 | 21 | identifier_name: 22 | excluded: 23 | - id 24 | 25 | child_config: child1.yml 26 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Directory.swift/DirectoryLevel1.swift: -------------------------------------------------------------------------------- 1 | // This is just a mock Swift file 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/EmptyFolder/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realm/SwiftLint/c1ffdfe8913c12398a3a05fe19844c1031fa7add/Tests/FrameworkTests/Resources/ProjectMock/EmptyFolder/.gitkeep -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Level0.swift: -------------------------------------------------------------------------------- 1 | // This is just a mock Swift file 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Level1/Level1.swift: -------------------------------------------------------------------------------- 1 | // This is just a mock Swift file 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Level1/Level2/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - force_try 3 | included: 4 | - "everything" 5 | excluded: 6 | - "the place where i committed many coding sins" 7 | line_length: 10000000000 8 | reporter: "json" 9 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Level1/Level2/Level2.swift: -------------------------------------------------------------------------------- 1 | // This is just a mock Swift file 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Level1/Level2/Level3/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - force_try 3 | - todo 4 | included: 5 | - "everything on level 3" 6 | excluded: 7 | - "the place where i committed many coding sins" 8 | line_length: 10000000000 9 | reporter: "json" 10 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Level1/Level2/Level3/Level3.swift: -------------------------------------------------------------------------------- 1 | // This is just a mock Swift file 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Level1/Level2/custom_rules.yml: -------------------------------------------------------------------------------- 1 | custom_rules: 2 | no_abcd: 3 | name: "Don't use abcd" 4 | regex: 'abcd' -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Level1/Level2/custom_rules_disabled.yml: -------------------------------------------------------------------------------- 1 | custom_rules: 2 | no_abcd: 3 | name: "Don't use abcd" 4 | regex: 'abcd' 5 | disabled_rules: 6 | - no_abc -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Level1/Level2/custom_rules_only.yml: -------------------------------------------------------------------------------- 1 | only_rules: 2 | - custom_rules 3 | 4 | custom_rules: 5 | no_abcd: 6 | name: "Don't use abcd" 7 | regex: 'abcd' 8 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/Level1/Level2/custom_rules_reconfig.yml: -------------------------------------------------------------------------------- 1 | custom_rules: 2 | no_abc: 3 | name: "Don't use abc" 4 | regex: 'abc' 5 | severity: 'error' 6 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/NestedConfig/Test/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - force_try 3 | 4 | parent_config: Sub/.swiftlint.yml 5 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/NestedConfig/Test/Main.swift: -------------------------------------------------------------------------------- 1 | // This is just a mock Swift file 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/NestedConfig/Test/Sub/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | opt_in_rules: 2 | - force_try 3 | 4 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/NestedConfig/Test/Sub/Sub.swift: -------------------------------------------------------------------------------- 1 | // This is just a mock Swift file 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Cycle1/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | line_length: 60 2 | 3 | parent_config: .swiftlint.yml 4 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Cycle2/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | line_length: 60 2 | 3 | parent_config: parent.yml 4 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Cycle2/parent.yml: -------------------------------------------------------------------------------- 1 | parent_config: parent.yml 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Cycle3/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | line_length: 60 2 | 3 | parent_config: parent.yml 4 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Cycle3/parent.yml: -------------------------------------------------------------------------------- 1 | parent_config: .swiftlint.yml 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Test1/expected.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1 3 | - Test/Test2 4 | - Test/Test1/Test 5 | - Test/Test2/Test 6 | - Test/Test1/Test/Test 7 | - Test/Test2/Test/Test 8 | 9 | line_length: 80 10 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Test1/main.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1/Test/Test 3 | - Test/Test2/Test/Test 4 | 5 | parent_config: parent1.yml 6 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Test1/parent1.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1/Test 3 | - Test/Test2/Test 4 | 5 | excluded: 6 | - Test/Test1/Test/Test 7 | - Test/Test2/Test/Test 8 | 9 | parent_config: parent2.yml 10 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Test1/parent2.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1 3 | - Test/Test2 4 | 5 | excluded: 6 | - Test/Test1/Test 7 | - Test/Test2/Test 8 | 9 | line_length: 80 10 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Test2/expected.yml: -------------------------------------------------------------------------------- 1 | opt_in_rules: 2 | - private_action 3 | 4 | disabled_rules: 5 | - empty_count 6 | - force_cast 7 | - private_outlet 8 | - trailing_closure 9 | 10 | line_length: 80 11 | 12 | identifier_name: 13 | excluded: 14 | - abc 15 | 16 | included: 17 | - Test/Test1 18 | - Test/Test2 19 | - Test/Test1/Test 20 | - Test/Test2/Test 21 | 22 | excluded: 23 | - Test/Test1/Test/Test 24 | - Test/Test2/Test/Test 25 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Test2/main.yml: -------------------------------------------------------------------------------- 1 | opt_in_rules: 2 | - identifier_name 3 | 4 | disabled_rules: 5 | - trailing_closure 6 | - empty_count 7 | 8 | line_length: 80 9 | 10 | identifier_name: 11 | excluded: 12 | - abc 13 | 14 | parent_config: parent1.yml 15 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Test2/parent1.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - private_outlet 3 | 4 | included: 5 | - Test/Test1/Test 6 | - Test/Test2/Test 7 | 8 | excluded: 9 | - Test/Test1/Test/Test 10 | - Test/Test2/Test/Test 11 | 12 | parent_config: parent2.yml 13 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/ParentConfig/Test2/parent2.yml: -------------------------------------------------------------------------------- 1 | opt_in_rules: 2 | - private_action 3 | - private_outlet 4 | - trailing_closure 5 | - empty_count 6 | 7 | disabled_rules: 8 | - force_cast 9 | - identifier_name 10 | 11 | line_length: 160 12 | 13 | included: 14 | - Test/Test1 15 | - Test/Test2 16 | 17 | excluded: 18 | - Test/Test1/Test 19 | - Test/Test2/Test 20 | 21 | identifier_name: 22 | excluded: 23 | - id 24 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/RemoteConfig/Child/child.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1/Test 3 | - Test/Test2/Test 4 | 5 | excluded: 6 | - Test/Test1/Test/Test 7 | - Test/Test2/Test/Test 8 | 9 | child_config: https://www.mock.com 10 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/RemoteConfig/Child/expected.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1 3 | - Test/Test2 4 | - Test/Test1/Test 5 | - Test/Test2/Test 6 | - Test/Test1/Test/Test 7 | - Test/Test2/Test/Test 8 | 9 | line_length: 80 10 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/RemoteConfig/Child/main.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1 3 | - Test/Test2 4 | 5 | excluded: 6 | - Test/Test1/Test 7 | - Test/Test2/Test 8 | 9 | line_length: 80 10 | 11 | child_config: child.yml 12 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/RemoteConfig/Cycle/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | line_length: 60 2 | 3 | child_config: https://www.mock.com 4 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/RemoteConfig/LocalRef/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | child_config: child1.yml 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/RemoteConfig/LocalRef/child1.yml: -------------------------------------------------------------------------------- 1 | child_config: https://www.mock.com 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/RemoteConfig/LocalRef/child2.yml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/RemoteConfig/Parent/expected.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1 3 | - Test/Test2 4 | - Test/Test1/Test 5 | - Test/Test2/Test 6 | - Test/Test1/Test/Test 7 | - Test/Test2/Test/Test 8 | 9 | line_length: 80 10 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/RemoteConfig/Parent/main.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1/Test/Test 3 | - Test/Test2/Test/Test 4 | 5 | parent_config: parent.yml 6 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/RemoteConfig/Parent/parent.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Test/Test1/Test 3 | - Test/Test2/Test 4 | 5 | excluded: 6 | - Test/Test1/Test/Test 7 | - Test/Test2/Test/Test 8 | 9 | parent_config: https://www.mock.com 10 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/custom.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - force_cast 3 | included: 4 | - "only a few things" 5 | excluded: 6 | - "the place where i committed many coding sins" 7 | line_length: 10000000000 8 | reporter: "json" 9 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/custom_included_excluded.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - "File1.swift" 3 | 4 | excluded: 5 | - "File2.swift" 6 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/custom_rules.yml: -------------------------------------------------------------------------------- 1 | custom_rules: 2 | no_abc: 3 | name: "Don't use abc" 4 | regex: 'abc' -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/ProjectMock/custom_rules_only.yml: -------------------------------------------------------------------------------- 1 | only_rules: 2 | - custom_rules 3 | 4 | custom_rules: 5 | no_abc: 6 | name: "Don't use abc" 7 | regex: 'abc' 8 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/test.txt: -------------------------------------------------------------------------------- 1 | // My file with 2 | // a pattern 3 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/Resources/test.yml: -------------------------------------------------------------------------------- 1 | dictionary1: 2 | bool: true 3 | int: 1 4 | double: 1.0 5 | string: string 6 | array: 7 | - true 8 | - 1 9 | - 1.0 10 | - string 11 | - bool: true 12 | int: 1 13 | double: 1.0 14 | string: string 15 | 16 | dictionary2: 17 | bool: true 18 | int: 1 19 | double: 1.0 20 | string: string 21 | array: 22 | - true 23 | - 1 24 | - 1.0 25 | - string 26 | - bool: true 27 | int: 1 28 | double: 1.0 29 | string: string 30 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/RulesTests.swift: -------------------------------------------------------------------------------- 1 | @testable import SwiftLintBuiltInRules 2 | 3 | final class RulesTests: SwiftLintTestCase { 4 | func testLeadingWhitespace() { 5 | verifyRule(LeadingWhitespaceRule.description, skipDisableCommandTests: true, 6 | testMultiByteOffsets: false, testShebang: false) 7 | } 8 | 9 | func testMark() { 10 | verifyRule(MarkRule.description, skipCommentTests: true) 11 | } 12 | 13 | func testRequiredEnumCase() { 14 | let configuration = ["NetworkResponsable": ["notConnected": "error"]] 15 | verifyRule(RequiredEnumCaseRule.description, ruleConfiguration: configuration) 16 | } 17 | 18 | func testTrailingNewline() { 19 | verifyRule(TrailingNewlineRule.description, commentDoesntViolate: false, 20 | stringDoesntViolate: false) 21 | } 22 | 23 | func testOrphanedDocComment() { 24 | verifyRule(OrphanedDocCommentRule.description, commentDoesntViolate: false, skipCommentTests: true) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Tests/FrameworkTests/StringViewExtensionTests.swift: -------------------------------------------------------------------------------- 1 | import SourceKittenFramework 2 | import XCTest 3 | 4 | final class StringViewExtensionTests: SwiftLintTestCase { 5 | func testByteOffsetInvalidCases() { 6 | let view = StringView("") 7 | 8 | XCTAssertNil(view.byteOffset(forLine: 0, bytePosition: 1)) 9 | XCTAssertNil(view.byteOffset(forLine: 1, bytePosition: 0)) 10 | XCTAssertNil(view.byteOffset(forLine: -10, bytePosition: 1)) 11 | XCTAssertNil(view.byteOffset(forLine: 0, bytePosition: -11)) 12 | XCTAssertNil(view.byteOffset(forLine: 2, bytePosition: 1)) 13 | } 14 | 15 | func testByteOffsetFromLineAndBytePosition() { 16 | XCTAssertEqual(StringView("").byteOffset(forLine: 1, bytePosition: 1), 0) 17 | XCTAssertEqual(StringView("a").byteOffset(forLine: 1, bytePosition: 1), 0) 18 | XCTAssertEqual(StringView("aaa").byteOffset(forLine: 1, bytePosition: 3), 2) 19 | XCTAssertEqual(StringView("a🍰a").byteOffset(forLine: 1, bytePosition: 6), 5) 20 | XCTAssertEqual(StringView("a🍰a\na").byteOffset(forLine: 2, bytePosition: 1), 7) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/TestHelpers/RuleDescription+Examples.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintFramework 2 | 3 | public extension RuleDescription { 4 | func with(nonTriggeringExamples: [Example]? = nil, 5 | triggeringExamples: [Example]? = nil, 6 | corrections: [Example: Example]? = nil) -> RuleDescription { 7 | RuleDescription(identifier: identifier, 8 | name: name, 9 | description: description, 10 | kind: kind, 11 | nonTriggeringExamples: nonTriggeringExamples ?? self.nonTriggeringExamples, 12 | triggeringExamples: triggeringExamples ?? self.triggeringExamples, 13 | corrections: corrections ?? self.corrections, 14 | deprecatedAliases: deprecatedAliases) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/TestHelpers/RuleMock.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintCore 2 | 3 | public struct RuleMock: Rule { 4 | var configurationDescription: some Documentable { RuleConfigurationOption.noOptions } 5 | 6 | public var configuration = SeverityConfiguration<Self>(.warning) 7 | 8 | public static let description = RuleDescription( 9 | identifier: "RuleMock", 10 | name: "", 11 | description: "", 12 | kind: .style 13 | ) 14 | 15 | public init() { /* conformance for test */ } 16 | public init(configuration _: Any) throws { self.init() } 17 | 18 | public func validate(file _: SwiftLintFile) -> [StyleViolation] { [] } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/TestHelpers/SwiftLintTestCase.swift: -------------------------------------------------------------------------------- 1 | import SwiftLintFramework 2 | import XCTest 3 | 4 | // swiftlint:disable:next balanced_xctest_lifecycle 5 | open class SwiftLintTestCase: XCTestCase { 6 | override open class func setUp() { 7 | super.setUp() 8 | RuleRegistry.registerAllRulesOnce() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/TestHelpers/TestResources.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum TestResources { 4 | public static func path(_ calleePath: String = #filePath) -> String { 5 | let folder = URL(fileURLWithPath: calleePath, isDirectory: false).deletingLastPathComponent() 6 | if let rootProjectDirectory = ProcessInfo.processInfo.environment["BUILD_WORKSPACE_DIRECTORY"] { 7 | return "\(rootProjectDirectory)/Tests/\(folder.lastPathComponent)/Resources" 8 | } 9 | return folder 10 | .appendingPathComponent("Resources") 11 | .path 12 | .absolutePathStandardized() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/generated_tests.bzl: -------------------------------------------------------------------------------- 1 | # GENERATED FILE. DO NOT EDIT! 2 | 3 | load(":test_macros.bzl", "generated_test_shard") 4 | 5 | def generated_tests(copts, strict_concurrency_copts): 6 | """Creates all generated test targets for SwiftLint rules. 7 | 8 | Args: 9 | copts: Common compiler options 10 | strict_concurrency_copts: Strict concurrency compiler options 11 | """ 12 | generated_test_shard("01", copts, strict_concurrency_copts) 13 | generated_test_shard("02", copts, strict_concurrency_copts) 14 | generated_test_shard("03", copts, strict_concurrency_copts) 15 | generated_test_shard("04", copts, strict_concurrency_copts) 16 | generated_test_shard("05", copts, strict_concurrency_copts) 17 | generated_test_shard("06", copts, strict_concurrency_copts) 18 | generated_test_shard("07", copts, strict_concurrency_copts) 19 | generated_test_shard("08", copts, strict_concurrency_copts) 20 | generated_test_shard("09", copts, strict_concurrency_copts) 21 | generated_test_shard("10", copts, strict_concurrency_copts) 22 | -------------------------------------------------------------------------------- /Tests/test_macros.bzl: -------------------------------------------------------------------------------- 1 | load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library", "swift_test") 2 | 3 | def generated_test_shard(shard_number, copts, strict_concurrency_copts): 4 | """Creates a single generated test shard with library and test targets. 5 | 6 | Args: 7 | shard_number: The shard number as a string 8 | copts: Common compiler options 9 | strict_concurrency_copts: Strict concurrency compiler options 10 | """ 11 | swift_library( 12 | name = "GeneratedTests_{}.library".format(shard_number), 13 | testonly = True, 14 | srcs = ["GeneratedTests/GeneratedTests_{}.swift".format(shard_number)], 15 | module_name = "GeneratedTests_{}".format(shard_number), 16 | package_name = "SwiftLint", 17 | deps = [ 18 | ":TestHelpers", 19 | ], 20 | copts = copts + strict_concurrency_copts, 21 | ) 22 | 23 | swift_test( 24 | name = "GeneratedTests_{}".format(shard_number), 25 | visibility = ["//visibility:public"], 26 | deps = [":GeneratedTests_{}.library".format(shard_number)], 27 | ) 28 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "SwiftLint") 2 | -------------------------------------------------------------------------------- /assets/custom-rule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realm/SwiftLint/c1ffdfe8913c12398a3a05fe19844c1031fa7add/assets/custom-rule.png -------------------------------------------------------------------------------- /assets/macstadium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realm/SwiftLint/c1ffdfe8913c12398a3a05fe19844c1031fa7add/assets/macstadium.png -------------------------------------------------------------------------------- /assets/realm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realm/SwiftLint/c1ffdfe8913c12398a3a05fe19844c1031fa7add/assets/realm.png -------------------------------------------------------------------------------- /assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realm/SwiftLint/c1ffdfe8913c12398a3a05fe19844c1031fa7add/assets/screenshot.png -------------------------------------------------------------------------------- /bazel/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "@rules_xcodeproj//xcodeproj:defs.bzl", 3 | "xcode_schemes", 4 | "xcodeproj", 5 | ) 6 | 7 | # Xcode Integration 8 | 9 | xcodeproj( 10 | name = "xcodeproj", 11 | install_directory = "", 12 | project_name = "SwiftLint", 13 | schemes = [ 14 | xcode_schemes.scheme( 15 | name = "SwiftLint", 16 | launch_action = xcode_schemes.launch_action( 17 | "//:swiftlint", 18 | args = [ 19 | "--progress", 20 | ], 21 | ), 22 | test_action = xcode_schemes.test_action([ 23 | "//Tests:BuiltInRulesTests", 24 | "//Tests:CLITests", 25 | "//Tests:ExtraRulesTests", 26 | "//Tests:FrameworkTests", 27 | "//Tests:GeneratedTests", 28 | "//Tests:IntegrationTests", 29 | "//Tests:MacroTests", 30 | ]), 31 | ), 32 | ], 33 | top_level_targets = [ 34 | "//:swiftlint", 35 | "//Tests:BuiltInRulesTests", 36 | "//Tests:CLITests", 37 | "//Tests:ExtraRulesTests", 38 | "//Tests:FrameworkTests", 39 | "//Tests:GeneratedTests", 40 | "//Tests:IntegrationTests", 41 | "//Tests:MacroTests", 42 | ], 43 | ) 44 | 45 | # Release Files 46 | 47 | filegroup( 48 | name = "release_files", 49 | srcs = glob(["*"]), 50 | visibility = ["//visibility:public"], 51 | ) 52 | -------------------------------------------------------------------------------- /bazel/CollectionConcurrencyKit.BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "@build_bazel_rules_swift//swift:swift.bzl", 3 | "swift_library", 4 | ) 5 | 6 | swift_library( 7 | name = "CollectionConcurrencyKit", 8 | srcs = ["Sources/CollectionConcurrencyKit.swift"], 9 | module_name = "CollectionConcurrencyKit", 10 | visibility = ["//visibility:public"], 11 | ) 12 | -------------------------------------------------------------------------------- /bazel/CryptoSwift.BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "@build_bazel_rules_swift//swift:swift.bzl", 3 | "swift_library", 4 | ) 5 | 6 | swift_library( 7 | name = "CryptoSwift", 8 | srcs = glob(["Sources/**/*.swift"]), 9 | module_name = "CryptoSwift", 10 | visibility = ["//visibility:public"], 11 | ) 12 | -------------------------------------------------------------------------------- /bazel/SWXMLHash.BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "@build_bazel_rules_swift//swift:swift.bzl", 3 | "swift_library", 4 | ) 5 | 6 | swift_library( 7 | name = "SWXMLHash", 8 | srcs = glob(["Source/**/*.swift"]), 9 | module_name = "SWXMLHash", 10 | visibility = ["//visibility:public"], 11 | ) 12 | -------------------------------------------------------------------------------- /bazel/SwiftArgumentParser.BUILD: -------------------------------------------------------------------------------- 1 | load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") 2 | 3 | swift_library( 4 | name = "ArgumentParserToolInfo", 5 | srcs = glob(["Sources/ArgumentParserToolInfo/**/*.swift"]), 6 | module_name = "ArgumentParserToolInfo", 7 | ) 8 | 9 | swift_library( 10 | name = "ArgumentParser", 11 | srcs = glob(["Sources/ArgumentParser/**/*.swift"]), 12 | module_name = "ArgumentParser", 13 | visibility = ["//visibility:public"], 14 | deps = [ 15 | ":ArgumentParserToolInfo", 16 | ], 17 | ) 18 | -------------------------------------------------------------------------------- /bazel/SwiftyTextTable.BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "@build_bazel_rules_swift//swift:swift.bzl", 3 | "swift_library", 4 | ) 5 | 6 | swift_library( 7 | name = "SwiftyTextTable", 8 | srcs = glob(["Source/**/*.swift"]), 9 | module_name = "SwiftyTextTable", 10 | visibility = ["//visibility:public"], 11 | ) 12 | -------------------------------------------------------------------------------- /bazel/deps.bzl: -------------------------------------------------------------------------------- 1 | def _extra_swift_sources_impl(ctx): 2 | ctx.file("WORKSPACE", "") 3 | ctx.file("empty.swift", "public func extraRules() -> [any Rule.Type] { [] }") 4 | label = ":empty" 5 | if ctx.attr.srcs: 6 | label = ctx.attr.srcs 7 | ctx.file("BUILD.bazel", """ 8 | filegroup( 9 | name = "empty", 10 | srcs = ["empty.swift"], 11 | ) 12 | 13 | alias( 14 | name = "extra_rules", 15 | actual = "{}", 16 | visibility = ["//visibility:public"], 17 | )""".format(label)) 18 | 19 | extra_swift_sources = repository_rule( 20 | implementation = _extra_swift_sources_impl, 21 | attrs = { 22 | "srcs": attr.label(allow_files = [".swift"]), 23 | }, 24 | ) 25 | 26 | def swiftlint_deps(): 27 | """Fetches SwiftLint dependencies""" 28 | if not native.existing_rule("build_bazel_rules_apple"): 29 | fail("error: this depends on rules_apple but that wasn't setup") 30 | 31 | if not native.existing_rule("build_bazel_rules_swift"): 32 | fail("error: this depends on rules_swift but that wasn't setup") 33 | 34 | if not native.existing_rule("swiftlint_extra_rules"): 35 | extra_swift_sources(name = "swiftlint_extra_rules") 36 | -------------------------------------------------------------------------------- /bazel/extensions.bzl: -------------------------------------------------------------------------------- 1 | """bzlmod module_extension for providing extra rule sources that should be loaded by swiftlint""" 2 | 3 | load(":deps.bzl", "extra_swift_sources") 4 | 5 | def _extra_rules(module_ctx): 6 | root_modules = [m for m in module_ctx.modules if m.is_root] 7 | if len(root_modules) > 1: 8 | fail("Expected at most one root module, found {}".format(", ".join([x.name for x in root_modules]))) 9 | 10 | if root_modules: 11 | root_module = root_modules[0] 12 | else: 13 | root_module = module_ctx.modules[0] 14 | 15 | kwargs = {} 16 | if root_module.tags.setup: 17 | kwargs["srcs"] = root_module.tags.setup[0].srcs 18 | 19 | extra_swift_sources( 20 | name = "swiftlint_extra_rules", 21 | **kwargs 22 | ) 23 | 24 | extra_rules = module_extension( 25 | implementation = _extra_rules, 26 | tag_classes = { 27 | "setup": tag_class(attrs = { 28 | "srcs": attr.label(allow_files = [".swift"]), 29 | }), 30 | }, 31 | ) 32 | -------------------------------------------------------------------------------- /tools/BUILD: -------------------------------------------------------------------------------- 1 | exports_files(["test-analyze.sh"]) 2 | -------------------------------------------------------------------------------- /tools/Version.swift.template: -------------------------------------------------------------------------------- 1 | /// A type describing the SwiftLint version. 2 | public struct Version: VersionComparable, Sendable { 3 | /// The string value for this version. 4 | public let value: String 5 | 6 | /// An alias for `value` required for protocol conformance. 7 | public var rawValue: String { 8 | value 9 | } 10 | 11 | /// The current SwiftLint version. 12 | public static let current = Self(value: "__VERSION__") 13 | 14 | /// Public initializer. 15 | /// 16 | /// - parameter value: The string value for this version. 17 | public init(value: String) { 18 | self.value = value 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tools/add-new-changelog-section.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | # Header with new section 6 | new_section=$(cat <<EOF 7 | # Changelog 8 | 9 | ## Main 10 | 11 | ### Breaking 12 | 13 | * None. 14 | 15 | ### Experimental 16 | 17 | * None. 18 | 19 | ### Enhancements 20 | 21 | * None. 22 | 23 | ### Bug Fixes 24 | 25 | * None. 26 | EOF 27 | ) 28 | 29 | # Read changelog skipping the first line 30 | changelog=$(tail -n +2 CHANGELOG.md) 31 | 32 | # Prepend the new section and a newline to the existing changelog 33 | { echo -e "$new_section"; echo "$changelog"; } > CHANGELOG.md 34 | -------------------------------------------------------------------------------- /tools/create-github-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | version="$1" 6 | 7 | # Generate Release Notes 8 | 9 | release_notes=$(mktemp) 10 | ./tools/generate-release-notes.sh "$version" > "$release_notes" 11 | 12 | # Create GitHub Release 13 | 14 | release_title="$(sed -n '3s/^## //p' CHANGELOG.md)" 15 | gh release create "$version" --title "$release_title" -F "$release_notes" --draft --verify-tag \ 16 | "bazel.tar.gz" \ 17 | "bazel.tar.gz.sha256" \ 18 | "portable_swiftlint.zip#Universal macOS Binary" \ 19 | "swiftlint_linux.zip#AMD64 Linux Binary" \ 20 | "SwiftLint.pkg#Universal macOS Installer" \ 21 | "SwiftLintBinary.artifactbundle.zip" 22 | 23 | rm "$release_notes" 24 | -------------------------------------------------------------------------------- /tools/get-version: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | cat Source/SwiftLintFramework/Models/Version.swift | awk -F '"' '{print $2}' | xargs 6 | -------------------------------------------------------------------------------- /tools/info.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0", 3 | "artifacts": { 4 | "swiftlint": { 5 | "version": "__VERSION__", 6 | "type": "executable", 7 | "variants": [ 8 | { 9 | "path": "swiftlint-__VERSION__-macos/bin/swiftlint", 10 | "supportedTriples": ["x86_64-apple-macosx", "arm64-apple-macosx"] 11 | }, 12 | { 13 | "path": "swiftlint-__VERSION__-linux-gnu/bin/swiftlint", 14 | "supportedTriples": ["x86_64-unknown-linux-gnu"] 15 | } 16 | ] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tools/test-analyze.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | readonly swiftlint="$RUNFILES_DIR/_main/swiftlint" 6 | if [[ ! -x "$swiftlint" ]]; then 7 | echo "SwiftLint not found at $swiftlint" 8 | exit 1 9 | fi 10 | 11 | # Change to workspace directory 12 | cd "$(dirname "$(readlink Package.swift)")" 13 | swift build --build-tests 14 | "$swiftlint" analyze --strict --compile-commands ".build/debug.yaml" 15 | -------------------------------------------------------------------------------- /tools/update-artifact-bundle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | readonly version="$1" 6 | readonly artifactbundle="SwiftLintBinary.artifactbundle.zip" 7 | readonly checksum="$(shasum -a 256 "$artifactbundle" | cut -d " " -f1 | xargs)" 8 | 9 | sed -i '' \ 10 | "s/.*\/releases\/download\/.*/ url: \"https:\/\/github.com\/realm\/SwiftLint\/releases\/download\/$version\/SwiftLintBinary\.artifactbundle\.zip\",/g" \ 11 | Package.swift 12 | 13 | sed -i '' \ 14 | "s/.*checksum.*/ checksum: \"$checksum\"/g" \ 15 | Package.swift 16 | --------------------------------------------------------------------------------