Skip to content

Commit

Permalink
Add headerFileName rule
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood committed May 29, 2023
1 parent 3a39a33 commit 5d3d47b
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 83 deletions.
5 changes: 5 additions & 0 deletions Rules.md
Expand Up @@ -18,6 +18,7 @@
* [extensionAccessControl](#extensionAccessControl)
* [fileHeader](#fileHeader)
* [genericExtensions](#genericExtensions)
* [headerFileName](#headerFileName)
* [hoistAwait](#hoistAwait)
* [hoistPatternLet](#hoistPatternLet)
* [hoistTry](#hoistTry)
Expand Down Expand Up @@ -785,6 +786,10 @@ Option | Description
</details>
<br/>

## headerFileName

Ensure file name reference in header matches actual file name.

## hoistAwait

Move inline `await` keyword(s) to start of expression.
Expand Down
2 changes: 1 addition & 1 deletion Snapshots/Consumer/Sources/ConsumerCompiler.swift
@@ -1,5 +1,5 @@
//
// Consumer.swift
// ConsumerCompiler.swift
// Consumer
//
// Created by Nick Lockwood on 03/03/2018.
Expand Down
2 changes: 1 addition & 1 deletion Snapshots/Expression/Tests/AnyExpressionTests.swift
@@ -1,5 +1,5 @@
//
// ExpressionTests.swift
// AnyExpressionTests.swift
// ExpressionTests
//
// Created by Nick Lockwood on 18/04/2017.
Expand Down
2 changes: 1 addition & 1 deletion Sources/JSONReporter.swift
@@ -1,5 +1,5 @@
//
// CommandLine.swift
// JSONReporter.swift
// SwiftFormat
//
// Created by Daniele Formichelli on 09/04/2021.
Expand Down
88 changes: 88 additions & 0 deletions Sources/ParsingHelpers.swift
Expand Up @@ -1944,6 +1944,94 @@ extension Formatter {
}
}

// Range of tokens forming file header comment
var headerCommentTokenRange: Range<Int>? {
guard !options.fragment else {
return nil
}
var start = 0
var lastHeaderTokenIndex = -1
if var startIndex = index(of: .nonSpaceOrLinebreak, after: -1) {
if tokens[startIndex] == .startOfScope("#!") {
guard let endIndex = index(of: .linebreak, after: startIndex) else {
return nil
}
startIndex = index(of: .nonSpaceOrLinebreak, after: endIndex) ?? endIndex
start = startIndex
lastHeaderTokenIndex = startIndex - 1
}
switch tokens[startIndex] {
case .startOfScope("//"):
if case let .commentBody(body)? = next(.nonSpace, after: startIndex) {
processCommentBody(body, at: startIndex)
defer {
processLinebreak()
processLinebreak()
}
if !isEnabled || (body.hasPrefix("/") && !body.hasPrefix("//")) ||
body.hasPrefix("swift-tools-version")
{
return nil
} else if body.isCommentDirective {
break
}
}
var lastIndex = startIndex
while let index = index(of: .linebreak, after: lastIndex) {
switch token(at: index + 1) ?? .space("") {
case .startOfScope("//"):
if case let .commentBody(body)? = next(.nonSpace, after: index + 1),
body.isCommentDirective
{
break
}
lastIndex = index
continue
case .linebreak:
lastHeaderTokenIndex = index + 1
case .space where token(at: index + 2)?.isLinebreak == true:
lastHeaderTokenIndex = index + 2
default:
break
}
break
}
case .startOfScope("/*"):
if case let .commentBody(body)? = next(.nonSpace, after: startIndex) {
processCommentBody(body, at: startIndex)
defer {
processLinebreak()
processLinebreak()
}
if !isEnabled || (body.hasPrefix("*") && !body.hasPrefix("**")) {
return nil
} else if body.isCommentDirective {
break
}
}
while let endIndex = index(of: .endOfScope("*/"), after: startIndex) {
lastHeaderTokenIndex = endIndex
if let linebreakIndex = index(of: .linebreak, after: endIndex) {
lastHeaderTokenIndex = linebreakIndex
}
guard let nextIndex = index(of: .nonSpace, after: lastHeaderTokenIndex) else {
break
}
guard tokens[nextIndex] == .startOfScope("/*") else {
if let endIndex = index(of: .nonSpaceOrLinebreak, after: lastHeaderTokenIndex) {
lastHeaderTokenIndex = endIndex - 1
}
break
}
startIndex = nextIndex
}
default:
break
}
}
return start ..< lastHeaderTokenIndex + 1
}

struct SwitchCaseRange {
let beforeDelimiterRange: Range<Int>
let delimiterToken: Token
Expand Down
2 changes: 1 addition & 1 deletion Sources/Reporter.swift
@@ -1,5 +1,5 @@
//
// Report.swift
// Reporter.swift
// SwiftFormat
//
// Created by Jonas Boberg on 2023/02/13.
Expand Down
106 changes: 31 additions & 75 deletions Sources/Rules.swift
Expand Up @@ -4994,7 +4994,9 @@ public struct _FormatRules {
options: ["header"],
sharedOptions: ["linebreaks"]
) { formatter in
guard !formatter.options.fragment else { return }
guard let headerRange = formatter.headerCommentTokenRange else {
return
}

let header: String
switch formatter.options.fileHeader {
Expand All @@ -5021,83 +5023,14 @@ public struct _FormatRules {
}
header = string
}
var start = 0
var lastHeaderTokenIndex = -1
if var startIndex = formatter.index(of: .nonSpaceOrLinebreak, after: -1) {
if formatter.tokens[startIndex] == .startOfScope("#!") {
guard let endIndex = formatter.index(of: .linebreak, after: startIndex) else {
return
}
startIndex = formatter.index(of: .nonSpaceOrLinebreak, after: endIndex) ?? endIndex
start = startIndex
lastHeaderTokenIndex = startIndex - 1
}
switch formatter.tokens[startIndex] {
case .startOfScope("//"):
if case let .commentBody(body)? = formatter.next(.nonSpace, after: startIndex) {
formatter.processCommentBody(body, at: startIndex)
if !formatter.isEnabled || (body.hasPrefix("/") && !body.hasPrefix("//")) ||
body.hasPrefix("swift-tools-version")
{
return
} else if body.isCommentDirective {
break
}
}
var lastIndex = startIndex
while let index = formatter.index(of: .linebreak, after: lastIndex) {
switch formatter.token(at: index + 1) ?? .space("") {
case .startOfScope("//"):
if case let .commentBody(body)? = formatter.next(.nonSpace, after: index + 1),
body.isCommentDirective
{
break
}
lastIndex = index
continue
case .linebreak:
lastHeaderTokenIndex = index + 1
case .space where formatter.token(at: index + 2)?.isLinebreak == true:
lastHeaderTokenIndex = index + 2
default:
break
}
break
}
case .startOfScope("/*"):
if case let .commentBody(body)? = formatter.next(.nonSpace, after: startIndex) {
formatter.processCommentBody(body, at: startIndex)
if !formatter.isEnabled || (body.hasPrefix("*") && !body.hasPrefix("**")) {
return
} else if body.isCommentDirective {
break
}
}
while let endIndex = formatter.index(of: .endOfScope("*/"), after: startIndex) {
lastHeaderTokenIndex = endIndex
if let linebreakIndex = formatter.index(of: .linebreak, after: endIndex) {
lastHeaderTokenIndex = linebreakIndex
}
guard let nextIndex = formatter.index(of: .nonSpace, after: lastHeaderTokenIndex) else {
break
}
guard formatter.tokens[nextIndex] == .startOfScope("/*") else {
if let endIndex = formatter.index(of: .nonSpaceOrLinebreak, after: lastHeaderTokenIndex) {
lastHeaderTokenIndex = endIndex - 1
}
break
}
startIndex = nextIndex
}
default:
break
}
}

if header.isEmpty {
formatter.removeTokens(in: start ..< lastHeaderTokenIndex + 1)
formatter.removeTokens(in: headerRange)
return
}

var headerTokens = tokenize(header)
var lastHeaderTokenIndex = headerRange.endIndex - 1
let endIndex = lastHeaderTokenIndex + headerTokens.count
if formatter.tokens.endIndex > endIndex, headerTokens == Array(formatter.tokens[
lastHeaderTokenIndex + 1 ... endIndex
Expand All @@ -5122,7 +5055,30 @@ public struct _FormatRules {
}) {
lastHeaderTokenIndex = index
}
formatter.replaceTokens(in: start ..< lastHeaderTokenIndex + 1, with: headerTokens)
formatter.replaceTokens(in: headerRange.startIndex ..< lastHeaderTokenIndex + 1, with: headerTokens)
}

/// Ensure file name reference in header matches actual file name
public let headerFileName = FormatRule(
help: "Ensure file name reference in header matches actual file name.",
runOnceOnly: true,
orderAfter: ["fileHeader"]
) { formatter in
guard let fileName = formatter.options.fileInfo.fileName,
let headerRange = formatter.headerCommentTokenRange,
fileName.hasSuffix(".swift")
else {
return
}

for i in headerRange {
guard case let .commentBody(body) = formatter.tokens[i] else {
continue
}
if body.hasSuffix(".swift"), body != fileName, !body.contains(where: { " /".contains($0) }) {
formatter.replaceToken(at: i, with: .commentBody(fileName))
}
}
}

/// Strip redundant `.init` from type instantiations
Expand Down
2 changes: 1 addition & 1 deletion Tests/EnumAssociableTests.swift
@@ -1,5 +1,5 @@
//
// EnumAssociableTest.swift
// EnumAssociableTests.swift
// SwiftFormat
//
// Created by Vincent Bernier on 13-02-18.
Expand Down
2 changes: 1 addition & 1 deletion Tests/OptionDescriptorTests.swift
@@ -1,5 +1,5 @@
//
// OptionDescriptorTest.swift
// OptionDescriptorTests.swift
// SwiftFormatTests
//
// Created by Vincent Bernier on 10-02-18.
Expand Down
17 changes: 17 additions & 0 deletions Tests/RulesTests+General.swift
Expand Up @@ -666,6 +666,23 @@ class GeneralTests: RulesTests {
testFormatting(for: input, rule: FormatRules.fileHeader, options: options)
}

// MARK: - headerFileName

func testHeaderFileNameReplaced() {
let input = """
// MyFile.swift
let foo = bar
"""
let output = """
// YourFile.swift
let foo = bar
"""
let options = FormatOptions(fileInfo: FileInfo(filePath: "~/YourFile.swift"))
testFormatting(for: input, output, rule: FormatRules.headerFileName, options: options)
}

// MARK: - strongOutlets

func testRemoveWeakFromOutlet() {
Expand Down
2 changes: 1 addition & 1 deletion Tests/RulesTests+Organization.swift
@@ -1,5 +1,5 @@
//
// RulesTests+Organize.swift
// RulesTests+Organization.swift
// SwiftFormatTests
//
// Created by Nick Lockwood on 04/09/2020.
Expand Down
2 changes: 1 addition & 1 deletion Tests/RulesTests+Spacing.swift
@@ -1,5 +1,5 @@
//
// SpacingRulesTests.swift
// RulesTests+Spacing.swift
// SwiftFormatTests
//
// Created by Nick Lockwood on 04/09/2020.
Expand Down

0 comments on commit 5d3d47b

Please sign in to comment.