11import ASTParser
22import Foundation
33import SuggestionModel
4+ import SwiftParser
5+ import SwiftSyntax
46
57protocol ASTReader {
68 func contextContainingRange(
@@ -44,7 +46,106 @@ struct SwiftASTReader: ASTReader {
4446 case propertyDeclaration = " property_declaration "
4547 case computedProperty = " computed_property "
4648 }
47-
49+
50+ final class SwiftScopeHierarchySyntaxVisitor : SyntaxVisitor {
51+ let tree : SyntaxProtocol
52+ let code : String
53+ let range : CursorRange
54+ private var _scopeHierarchy : [ SyntaxProtocol ] = [ ]
55+
56+ /// The nodes containing the current range, sorted from inner to outer.
57+ func findScopeHierarchy( _ node: some SyntaxProtocol ) -> [ SyntaxProtocol ] {
58+ walk ( node)
59+ return _scopeHierarchy. sorted { $0. position. utf8Offset > $1. position. utf8Offset }
60+ }
61+
62+ /// The nodes containing the current range, sorted from inner to outer.
63+ func findScopeHierarchy( ) -> [ SyntaxProtocol ] {
64+ walk ( tree)
65+ return _scopeHierarchy. sorted { $0. position. utf8Offset > $1. position. utf8Offset }
66+ }
67+
68+ init ( tree: SyntaxProtocol , code: String , range: CursorRange ) {
69+ self . tree = tree
70+ self . code = code
71+ self . range = range
72+ super. init ( viewMode: . all)
73+ }
74+
75+ func skipChildrenIfPossible( _ node: SyntaxProtocol ) -> SyntaxVisitorContinueKind {
76+ if !nodeContainsRange( node) { return . skipChildren }
77+ return . visitChildren
78+ }
79+
80+ func captureNodeIfPossible( _ node: SyntaxProtocol ) -> SyntaxVisitorContinueKind {
81+ if !nodeContainsRange( node) { return . skipChildren }
82+ _scopeHierarchy. append ( node)
83+ return . visitChildren
84+ }
85+
86+ func nodeContainsRange( _ node: SyntaxProtocol ) -> Bool {
87+ let sourceRange = node. sourceRange ( converter: . init( file: code, tree: tree) )
88+ let cursorRange = CursorRange ( sourceRange: sourceRange)
89+ return cursorRange. contains ( range)
90+ }
91+
92+ // skip if possible
93+
94+ override func visit( _ node: CodeBlockItemSyntax ) -> SyntaxVisitorContinueKind {
95+ skipChildrenIfPossible ( node)
96+ }
97+
98+ override func visit( _ node: MemberDeclBlockSyntax ) -> SyntaxVisitorContinueKind {
99+ skipChildrenIfPossible ( node)
100+ }
101+
102+ override func visit( _ node: MemberDeclListItemSyntax ) -> SyntaxVisitorContinueKind {
103+ skipChildrenIfPossible ( node)
104+ }
105+
106+ // capture if possible
107+
108+ override func visit( _ node: StructDeclSyntax ) -> SyntaxVisitorContinueKind {
109+ captureNodeIfPossible ( node)
110+ }
111+
112+ override func visit( _ node: ClassDeclSyntax ) -> SyntaxVisitorContinueKind {
113+ captureNodeIfPossible ( node)
114+ }
115+
116+ override func visit( _ node: EnumDeclSyntax ) -> SyntaxVisitorContinueKind {
117+ captureNodeIfPossible ( node)
118+ }
119+
120+ override func visit( _ node: ActorDeclSyntax ) -> SyntaxVisitorContinueKind {
121+ captureNodeIfPossible ( node)
122+ }
123+
124+ override func visit( _ node: MacroDeclSyntax ) -> SyntaxVisitorContinueKind {
125+ captureNodeIfPossible ( node)
126+ }
127+
128+ override func visit( _ node: MacroExpansionDeclSyntax ) -> SyntaxVisitorContinueKind {
129+ captureNodeIfPossible ( node)
130+ }
131+
132+ override func visit( _ node: ProtocolDeclSyntax ) -> SyntaxVisitorContinueKind {
133+ captureNodeIfPossible ( node)
134+ }
135+
136+ override func visit( _ node: ExtensionDeclSyntax ) -> SyntaxVisitorContinueKind {
137+ captureNodeIfPossible ( node)
138+ }
139+
140+ override func visit( _ node: FunctionDeclSyntax ) -> SyntaxVisitorContinueKind {
141+ captureNodeIfPossible ( node)
142+ }
143+
144+ override func visit( _ node: SubscriptDeclSyntax ) -> SyntaxVisitorContinueKind {
145+ captureNodeIfPossible ( node)
146+ }
147+ }
148+
48149 func createExtraKnowledge( _ code: String ) -> String {
49150 var all = [ String] ( )
50151 if code. contains ( " macro " ) {
@@ -57,6 +158,99 @@ struct SwiftASTReader: ASTReader {
57158 _ range: CursorRange ,
58159 code: String ,
59160 codeLines: [ String ]
161+ ) -> CodeContext {
162+ let tree = Parser . parse ( source: code)
163+ let visitor = SwiftScopeHierarchySyntaxVisitor ( tree: tree, code: code, range: range)
164+ let nodes = visitor. findScopeHierarchy ( )
165+
166+ func convertRange( _ node: SyntaxProtocol ) -> CursorRange {
167+ . init( sourceRange: node. sourceRange ( converter: . init( file: code, tree: tree) ) )
168+ }
169+
170+ if let node = nodes. first {
171+ switch node. kind {
172+ case . structDecl:
173+ guard let node = node as? StructDeclSyntax else { break }
174+
175+ return . init( scope: . scope(
176+ type: node. structKeyword. text,
177+ identifier: node. identifier. text,
178+ range: convertRange ( node)
179+ ) )
180+ case . classDecl:
181+ guard let node = node as? ClassDeclSyntax else { break }
182+
183+ return . init( scope: . scope(
184+ type: node. classKeyword. text,
185+ identifier: node. identifier. text,
186+ range: convertRange ( node)
187+ ) )
188+ case . enumDecl:
189+ guard let node = node as? EnumDeclSyntax else { break }
190+
191+ return . init( scope: . scope(
192+ type: node. enumKeyword. text,
193+ identifier: node. identifier. text,
194+ range: convertRange ( node)
195+ ) )
196+ case . actorDecl:
197+ guard let node = node as? ActorDeclSyntax else { break }
198+
199+ return . init( scope: . scope(
200+ type: node. actorKeyword. text,
201+ identifier: node. identifier. text,
202+ range: convertRange ( node)
203+ ) )
204+ case . macroDecl:
205+ guard let node = node as? MacroDeclSyntax else { break }
206+
207+ return . init( scope: . scope(
208+ type: node. macroKeyword. text,
209+ identifier: node. identifier. text,
210+ range: convertRange ( node)
211+ ) )
212+ case . macroExpansionDecl:
213+ guard let node = node as? MacroExpansionDeclSyntax else { break }
214+
215+ return . init( scope: . scope(
216+ type: " macro expansion " ,
217+ identifier: node. macro. text,
218+ range: convertRange ( node)
219+ ) )
220+ case . protocolDecl:
221+ guard let node = node as? ProtocolDeclSyntax else { break }
222+
223+ return . init( scope: . scope(
224+ type: node. protocolKeyword. text,
225+ identifier: node. identifier. text,
226+ range: convertRange ( node)
227+ ) )
228+ case . extensionDecl:
229+ guard let node = node as? ExtensionDeclSyntax else { break }
230+
231+ return . init( scope: . scope(
232+ type: node. extensionKeyword. text,
233+ identifier: node. extendedType. description,
234+ range: convertRange ( node)
235+ ) )
236+ case . functionDecl:
237+ guard let node = node as? FunctionDeclSyntax else { break }
238+
239+ return . init( scope: . scope(
240+ type: node. funcKeyword. text,
241+ identifier: node. identifier. text,
242+ range: convertRange ( node)
243+ ) )
244+ }
245+ }
246+
247+ return . init( scope: . top)
248+ }
249+
250+ func contextContainingRange2(
251+ _ range: CursorRange ,
252+ code: String ,
253+ codeLines: [ String ]
60254 ) -> CodeContext {
61255 let parser = ASTParser ( language: . swift)
62256 guard let tree = parser. parse ( code) else {
@@ -162,3 +356,12 @@ struct SwiftASTReader: ASTReader {
162356 }
163357}
164358
359+ extension CursorRange {
360+ init ( sourceRange: SourceRange ) {
361+ self . init (
362+ start: . init( line: sourceRange. start. line - 1 , character: sourceRange. start. column - 1 ) ,
363+ end: . init( line: sourceRange. end. line - 1 , character: sourceRange. end. column - 1 )
364+ )
365+ }
366+ }
367+
0 commit comments