Introduce basic Stack type (#4922)

This commit is contained in:
Danny Mösch 2023-04-23 11:12:35 +02:00 committed by GitHub
parent 46ff727a13
commit c241935635
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 28 deletions

View File

@ -0,0 +1,37 @@
/// A basic stack type implementing the LIFO principle - only the last inserted element can be accessed and removed.
struct Stack<Element> {
private var elements = [Element]()
var isEmpty: Bool {
elements.isEmpty
}
var count: Int {
elements.count
}
mutating func push(_ element: Element) {
elements.append(element)
}
@discardableResult
mutating func pop() -> Element? {
elements.popLast()
}
func peek() -> Element? {
elements.last
}
}
extension Stack: CustomDebugStringConvertible where Element == CustomDebugStringConvertible {
var debugDescription: String {
let intermediateElements = count > 1 ? elements[1 ..< count - 1] : []
return """
Stack with \(count) elements:
first: \(elements.first?.debugDescription ?? "")
intermediate: \(intermediateElements.map(\.debugDescription).joined(separator: ", "))
last: \(peek()?.debugDescription ?? "")
"""
}
}

View File

@ -59,57 +59,57 @@ private class Visitor: ViolationsSyntaxVisitor {
case skipReferences
}
private var parentDeclScopes = [ParentDeclBehavior]()
private var variableDeclScopes = [VariableDeclBehavior]()
private var parentDeclScopes = Stack<ParentDeclBehavior>()
private var variableDeclScopes = Stack<VariableDeclBehavior>()
private(set) var corrections = [(start: AbsolutePosition, end: AbsolutePosition)]()
override func visit(_ node: ActorDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.append(.likeClass(name: node.identifier.text))
parentDeclScopes.push(.likeClass(name: node.identifier.text))
return .skipChildren
}
override func visitPost(_ node: ActorDeclSyntax) {
_ = parentDeclScopes.popLast()
parentDeclScopes.pop()
}
override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.append(.likeClass(name: node.identifier.text))
parentDeclScopes.push(.likeClass(name: node.identifier.text))
return .visitChildren
}
override func visitPost(_ node: ClassDeclSyntax) {
_ = parentDeclScopes.popLast()
parentDeclScopes.pop()
}
override func visit(_ node: CodeBlockSyntax) -> SyntaxVisitorContinueKind {
variableDeclScopes.append(.handleReferences)
variableDeclScopes.push(.handleReferences)
return .visitChildren
}
override func visitPost(_ node: CodeBlockSyntax) {
_ = variableDeclScopes.popLast()
variableDeclScopes.pop()
}
override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.append(.likeStruct(node.identifier.text))
parentDeclScopes.push(.likeStruct(node.identifier.text))
return .visitChildren
}
override func visitPost(_ node: EnumDeclSyntax) {
_ = parentDeclScopes.popLast()
parentDeclScopes.pop()
}
override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.append(.skipReferences)
parentDeclScopes.push(.skipReferences)
return .visitChildren
}
override func visitPost(_ node: ExtensionDeclSyntax) {
_ = parentDeclScopes.popLast()
parentDeclScopes.pop()
}
override func visit(_ node: MemberAccessExprSyntax) -> SyntaxVisitorContinueKind {
if case .likeClass = parentDeclScopes.last {
if case .likeClass = parentDeclScopes.peek() {
if node.name.tokenKind == .keyword(.self) {
return .skipChildren
}
@ -124,62 +124,62 @@ private class Visitor: ViolationsSyntaxVisitor {
!parent.is(ArrayElementSyntax.self) else {
return
}
if parent.is(FunctionCallExprSyntax.self), case .likeClass = parentDeclScopes.last {
if parent.is(FunctionCallExprSyntax.self), case .likeClass = parentDeclScopes.peek() {
return
}
addViolation(on: node.identifier)
}
override func visit(_ node: MemberDeclBlockSyntax) -> SyntaxVisitorContinueKind {
if case .likeClass = parentDeclScopes.last {
variableDeclScopes.append(.skipReferences)
if case .likeClass = parentDeclScopes.peek() {
variableDeclScopes.push(.skipReferences)
} else {
variableDeclScopes.append(.handleReferences)
variableDeclScopes.push(.handleReferences)
}
return .visitChildren
}
override func visitPost(_ node: MemberDeclBlockSyntax) {
_ = variableDeclScopes.popLast()
variableDeclScopes.pop()
}
override func visit(_ node: MacroExpansionExprSyntax) -> SyntaxVisitorContinueKind {
if case .likeClass = parentDeclScopes.last, case .identifier("selector") = node.macro.tokenKind {
if case .likeClass = parentDeclScopes.peek(), case .identifier("selector") = node.macro.tokenKind {
return .visitChildren
}
return .skipChildren
}
override func visit(_ node: ParameterClauseSyntax) -> SyntaxVisitorContinueKind {
if case .likeStruct = parentDeclScopes.last {
if case .likeStruct = parentDeclScopes.peek() {
return .visitChildren
}
return .skipChildren
}
override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.append(.skipReferences)
parentDeclScopes.push(.skipReferences)
return .skipChildren
}
override func visitPost(_ node: ProtocolDeclSyntax) {
_ = parentDeclScopes.popLast()
parentDeclScopes.pop()
}
override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.append(.likeStruct(node.identifier.text))
parentDeclScopes.push(.likeStruct(node.identifier.text))
return .visitChildren
}
override func visitPost(_ node: StructDeclSyntax) {
_ = parentDeclScopes.popLast()
parentDeclScopes.pop()
}
override func visitPost(_ node: SimpleTypeIdentifierSyntax) {
guard let parent = node.parent else {
return
}
if case .likeClass = parentDeclScopes.last,
if case .likeClass = parentDeclScopes.peek(),
parent.is(GenericArgumentSyntax.self) || parent.is(ReturnClauseSyntax.self) {
// Type is a generic parameter or the return type of a function.
return
@ -191,7 +191,7 @@ private class Visitor: ViolationsSyntaxVisitor {
}
override func visit(_ node: TypeAnnotationSyntax) -> SyntaxVisitorContinueKind {
guard case .likeStruct = parentDeclScopes.last else {
guard case .likeStruct = parentDeclScopes.peek() else {
return .skipChildren
}
if let varDecl = node.parent?.parent?.parent?.as(VariableDeclSyntax.self) {
@ -208,14 +208,14 @@ private class Visitor: ViolationsSyntaxVisitor {
// Variable declaration is a computed property.
return .visitChildren
}
if case .handleReferences = variableDeclScopes.last {
if case .handleReferences = variableDeclScopes.peek() {
return .visitChildren
}
return .skipChildren
}
private func addViolation(on node: TokenSyntax) {
if let parentName = parentDeclScopes.last?.parentName, node.tokenKind == .identifier(parentName) {
if let parentName = parentDeclScopes.peek()?.parentName, node.tokenKind == .identifier(parentName) {
violations.append(node.positionAfterSkippingLeadingTrivia)
corrections.append(
(start: node.positionAfterSkippingLeadingTrivia, end: node.endPositionBeforeTrailingTrivia)