@@ -25,20 +25,21 @@ extension SyntaxProtocol {
2525 }
2626}
2727
28+ /// Provide common functionality for specialized scope implementatations.
2829protocol Scope {
30+ /// The parent of this scope.
2931 var parent : Scope ? { get }
3032
33+ /// Syntax node that introduces this protocol.
3134 var sourceSyntax : SyntaxProtocol { get }
3235
36+ /// Returns the declaration `name` refers to at a particular syntax node location.
3337 func getDeclarationFor( name: String , at syntax: SyntaxProtocol ) -> Syntax ?
3438}
3539
3640extension Scope {
37- var parent : Scope ? {
38- getParentScope ( forSyntax: sourceSyntax)
39- }
40-
41- private func getParentScope( forSyntax syntax: SyntaxProtocol ? ) -> Scope ? {
41+ /// Recursively walks up syntax tree and finds the closest scope other than this scope.
42+ func getParentScope( forSyntax syntax: SyntaxProtocol ? ) -> Scope ? {
4243 if let lookedUpScope = syntax? . scope, lookedUpScope. sourceSyntax. id == syntax? . id {
4344 return getParentScope ( forSyntax: sourceSyntax. parent)
4445 } else {
@@ -48,42 +49,35 @@ extension Scope {
4849
4950 // MARK: - lookupLabeledStmts
5051
52+ /// Given syntax node position, returns all available labeled statements.
5153 func lookupLabeledStmts( at syntax: SyntaxProtocol ) -> [ LabeledStmtSyntax ] {
52- var result = [ LabeledStmtSyntax] ( )
53- lookupLabeledStmtsHelper ( at: syntax. parent, accumulator: & result)
54- return result
54+ return lookupLabeledStmtsHelper ( at: syntax. parent, accumulator: [ ] )
5555 }
5656
57- private func lookupLabeledStmtsHelper( at syntax: Syntax ? , accumulator: inout [ LabeledStmtSyntax ] ) {
58- guard let syntax, !syntax. is ( MemberBlockSyntax . self) else { return }
57+ /// Helper method to recursively collect labeled statements from the syntax node's parents.
58+ private func lookupLabeledStmtsHelper( at syntax: Syntax ? , accumulator: [ LabeledStmtSyntax ] ) -> [ LabeledStmtSyntax ] {
59+ guard let syntax, !syntax. is ( MemberBlockSyntax . self) else { return accumulator }
5960 if let labeledStmtSyntax = syntax. as ( LabeledStmtSyntax . self) {
60- accumulator. append ( labeledStmtSyntax)
61- lookupLabeledStmtsHelper ( at: labeledStmtSyntax. parent, accumulator: & accumulator)
61+ return lookupLabeledStmtsHelper ( at: labeledStmtSyntax. parent, accumulator: accumulator + [ labeledStmtSyntax] )
6262 } else {
63- lookupLabeledStmtsHelper ( at: syntax. parent, accumulator: & accumulator)
63+ return lookupLabeledStmtsHelper ( at: syntax. parent, accumulator: accumulator)
6464 }
6565 }
6666
6767 // MARK: - lookupFallthroughSourceAndDest
6868
69- func lookupFallthroughSourceAndDest( at syntax: SyntaxProtocol ) -> ( SwitchCaseSyntax ? , SwitchCaseSyntax ? ) {
70- guard let originalSwitchCase = lookupClosestSwitchCaseSyntaxAncestor ( at: syntax) else { return ( nil , nil ) }
69+ /// Given syntax node position, returns the current switch case and it's fallthrough destination.
70+ func lookupFallthroughSourceAndDestination( at syntax: SyntaxProtocol ) -> ( SwitchCaseSyntax ? , SwitchCaseSyntax ? ) {
71+ guard let originalSwitchCase = syntax. ancestorOrSelf ( mapping: { $0. as ( SwitchCaseSyntax . self) } ) else {
72+ return ( nil , nil )
73+ }
7174
7275 let nextSwitchCase = lookupNextSwitchCase ( at: originalSwitchCase)
7376
7477 return ( originalSwitchCase, nextSwitchCase)
7578 }
7679
77- private func lookupClosestSwitchCaseSyntaxAncestor( at syntax: SyntaxProtocol ? ) -> SwitchCaseSyntax ? {
78- guard let syntax else { return nil }
79-
80- if let switchCaseSyntax = syntax. as ( SwitchCaseSyntax . self) {
81- return switchCaseSyntax
82- } else {
83- return lookupClosestSwitchCaseSyntaxAncestor ( at: syntax. parent)
84- }
85- }
86-
80+ /// Given a switch case, returns the case that follows according to the parent.
8781 private func lookupNextSwitchCase( at switchCaseSyntax: SwitchCaseSyntax ) -> SwitchCaseSyntax ? {
8882 guard let switchCaseListSyntax = switchCaseSyntax. parent? . as ( SwitchCaseListSyntax . self) else { return nil }
8983
@@ -104,30 +98,32 @@ extension Scope {
10498
10599 // MARK: - lookupCatchNode
106100
101+ /// Given syntax node position, returns the closest ancestor catch node.
107102 func lookupCatchNode( at syntax: Syntax ) -> Syntax ? {
108103 return lookupCatchNodeHelper ( at: syntax, traversedCatchClause: false )
109104 }
110105
106+ /// Given syntax node location, finds where an error could be caught. If set to `true`, `traverseCatchClause`lookup will skip the next do statement.
111107 private func lookupCatchNodeHelper( at syntax: Syntax ? , traversedCatchClause: Bool ) -> Syntax ? {
112108 guard let syntax else { return nil }
113109
114- switch syntax. syntaxNodeType {
115- case is DoStmtSyntax . Type :
110+ switch syntax. as ( SyntaxEnum . self ) {
111+ case . doStmt :
116112 if traversedCatchClause {
117113 return lookupCatchNodeHelper ( at: syntax. parent, traversedCatchClause: false )
118114 } else {
119115 return syntax
120116 }
121- case is CatchClauseSyntax . Type :
117+ case . catchClause :
122118 return lookupCatchNodeHelper ( at: syntax. parent, traversedCatchClause: true )
123- case is TryExprSyntax . Type :
124- if syntax . as ( TryExprSyntax . self ) ! . questionOrExclamationMark != nil {
119+ case . tryExpr ( let tryExpr ) :
120+ if tryExpr . questionOrExclamationMark != nil {
125121 return syntax
126122 } else {
127123 return lookupCatchNodeHelper ( at: syntax. parent, traversedCatchClause: traversedCatchClause)
128124 }
129- case is FunctionDeclSyntax . Type :
130- if syntax . as ( FunctionDeclSyntax . self ) ! . signature. effectSpecifiers? . throwsClause != nil {
125+ case . functionDecl ( let functionDecl ) :
126+ if functionDecl . signature. effectSpecifiers? . throwsClause != nil {
131127 return syntax
132128 } else {
133129 return lookupCatchNodeHelper ( at: syntax. parent, traversedCatchClause: traversedCatchClause)
0 commit comments