Skip to content

Commit

Permalink
Add workaround to avoid stack overflow in debug (#3963)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelofabri authored May 1, 2022
1 parent bc7917b commit ebc7739
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ private var commandsCache = Cache({ file -> [Command] in
return []
}
let locationConverter = SourceLocationConverter(file: file.path ?? "<nopath>", tree: tree)

let visitor = CommandVisitor(locationConverter: locationConverter)
visitor.walk(tree)
return visitor.commands
return visitor.walk(tree: tree, handler: \.commands)
})

private var syntaxMapCache = Cache({ file in
Expand Down
46 changes: 46 additions & 0 deletions Source/SwiftLintFramework/Extensions/SyntaxVisitor+SwiftLint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Foundation
import SwiftSyntax

// workaround for https://bugs.swift.org/browse/SR-10121 so we can use `Self` in a closure
protocol SwiftLintSyntaxVisitor: SyntaxVisitor {}
extension SyntaxVisitor: SwiftLintSyntaxVisitor {}

extension SwiftLintSyntaxVisitor {
func walk<T>(tree: SourceFileSyntax, handler: (Self) -> T) -> T {
#if DEBUG
// workaround for stack overflow when running in debug
// https://bugs.swift.org/browse/SR-11170
let lock = NSLock()
let work = DispatchWorkItem {
lock.lock()
self.walk(tree)
lock.unlock()
}
let thread = Thread {
work.perform()
}

thread.stackSize = 8 << 20 // 8 MB.
thread.start()
work.wait()

lock.lock()
defer {
lock.unlock()
}

return handler(self)
#else
walk(tree)
return handler(self)
#endif
}

func walk<T>(file: SwiftLintFile, handler: (Self) -> [T]) -> [T] {
guard let syntaxTree = file.syntaxTree else {
return []
}

return walk(tree: syntaxTree, handler: handler)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@ public struct ForceCastRule: ConfigurationProviderRule, AutomaticTestableRule {
)

public func validate(file: SwiftLintFile) -> [StyleViolation] {
guard let tree = file.syntaxTree else { return [] }

let visitor = ForceCastRuleVisitor()
visitor.walk(tree)
return visitor.positions.map { position in
return visitor.walk(file: file, handler: \.positions).map { position in
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: file, byteOffset: ByteCount(position)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,10 @@ public struct ReturnValueFromVoidFunctionRule: ConfigurationProviderRule, OptInR
)

public func validate(file: SwiftLintFile) -> [StyleViolation] {
guard let tree = file.syntaxTree else {
return []
}

let visitor = ReturnValueFromVoidFunctionVisitor()
visitor.walk(tree)
return visitor.violations(for: self, in: file)
return visitor.walk(file: file) { visitor in
visitor.violations(for: self, in: file)
}
}
}

Expand Down
23 changes: 9 additions & 14 deletions Source/SwiftLintFramework/Rules/Idiomatic/SyntacticSugarRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,10 @@ public struct SyntacticSugarRule: CorrectableRule, ConfigurationProviderRule, Au
)

public func validate(file: SwiftLintFile) -> [StyleViolation] {
guard let tree = file.syntaxTree else { return [] }

let visitor = SyntacticSugarRuleVisitor()
visitor.walk(tree)

let allViolations = flattenViolations(visitor.violations)
return allViolations.map { violation in
return visitor.walk(file: file) { visitor in
flattenViolations(visitor.violations)
}.map { violation in
return StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: file, byteOffset: ByteCount(violation.position)),
Expand All @@ -37,17 +34,15 @@ public struct SyntacticSugarRule: CorrectableRule, ConfigurationProviderRule, Au
}

public func correct(file: SwiftLintFile) -> [Correction] {
guard let tree = file.syntaxTree else { return [] }

let visitor = SyntacticSugarRuleVisitor()
visitor.walk(tree)
return visitor.walk(file: file) { visitor in
var context = CorrectingContext(rule: self, file: file, contents: file.contents)
context.correctViolations(visitor.violations)

var context = CorrectingContext(rule: self, file: file, contents: file.contents)
context.correctViolations(visitor.violations)
file.write(context.contents)

file.write(context.contents)

return context.corrections
return context.corrections
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,10 @@ public struct UnavailableConditionRule: ConfigurationProviderRule, AutomaticTest
)

public func validate(file: SwiftLintFile) -> [StyleViolation] {
guard let tree = file.syntaxTree else {
return []
}

let visitor = UnavailableConditionRuleVisitor()
visitor.walk(tree)
return visitor.positions.map { position in
return visitor.walk(file: file) {
$0.positions
}.map { position in
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: file, byteOffset: ByteCount(position.utf8Offset)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,10 @@ public struct CommaInheritanceRule: SubstitutionCorrectableRule, ConfigurationPr
}

public func violationRanges(in file: SwiftLintFile) -> [NSRange] {
guard let tree = file.syntaxTree else {
return []
}

let visitor = CommaInheritanceRuleVisitor()
visitor.walk(tree)
return visitor.violationRanges.compactMap {
return visitor.walk(file: file) { visitor -> [ByteRange] in
visitor.violationRanges
}.compactMap {
file.stringView.byteRangeToNSRange($0)
}
}
Expand Down

0 comments on commit ebc7739

Please sign in to comment.