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