@@ -52,21 +52,45 @@ class MultiFileContextManager {
5252 var result : [ String : SymbolContent ] = [ : ]
5353
5454 for file in fileContents {
55- guard let fileURL = URL ( string: file. fileURL) else { continue }
56- do {
57- let sourceFile = Parser . parse ( source: file. content)
58- let converter = SourceLocationConverter ( fileName: file. fileURL, tree: sourceFile)
59- let collector = DeclarationCollector ( sourceLocationConverter: converter, sourceText: file. content)
60- collector. walk ( sourceFile)
61- result [ file. fileName] = file. mapToSymbolContent ( symbols: collector. symbols)
62- } catch {
63- print ( " SwiftSyntax parse failed for \( file. fileURL) : " , error)
55+ let sourceFile = Parser . parse ( source: file. content)
56+ let converter = SourceLocationConverter ( fileName: file. fileURL, tree: sourceFile)
57+ let collector = DeclarationCollector ( sourceLocationConverter: converter, sourceText: file. content)
58+ collector. walk ( sourceFile)
59+ var symbols : [ SymbolContent ] = collector. symbols. map { symbol in
60+ SymbolContent ( fileURL: file. fileURL, content: file. content, symbol: symbol)
61+ }
62+ mergeExtensionsIntoBaseDeclarations ( & symbols)
63+ for symbol in symbols {
64+ result [ symbol. symbol. name] = symbol
6465 }
6566 }
6667
6768 return result
6869 }
6970
71+ private func mergeExtensionsIntoBaseDeclarations( _ symbols: inout [ SymbolContent ] ) {
72+ var indexesToRemove : [ Int ] = [ ]
73+
74+ for (index, symbol) in symbols. enumerated ( ) {
75+ guard symbol. symbol. kind == . extensionWord else { continue }
76+
77+ if let targetIndex = symbols. firstIndex ( where: {
78+ $0. symbol. name == symbol. symbol. name &&
79+ $0. symbol. kind != . extensionWord
80+ } ) {
81+ var target = symbols [ targetIndex]
82+ target. symbol. extensions. append ( symbol)
83+ symbols [ targetIndex] = target
84+
85+ indexesToRemove. append ( index)
86+ }
87+ }
88+
89+ for index in indexesToRemove. sorted ( by: > ) {
90+ symbols. remove ( at: index)
91+ }
92+ }
93+
7094}
7195
7296struct FileContent {
@@ -80,16 +104,10 @@ struct FileContent {
80104 }
81105}
82106
83- extension FileContent {
84- func mapToSymbolContent( symbols: [ SymbolInfo ] ) -> SymbolContent {
85- SymbolContent ( fileURL: fileURL, content: content, symbols: symbols)
86- }
87- }
88-
89107struct SymbolContent {
90108 let fileURL : String
91109 let content : String
92- let symbols : [ SymbolInfo ]
110+ var symbol : SymbolInfo
93111}
94112
95113enum ClassificationKeywords : String {
@@ -107,10 +125,11 @@ enum ClassificationKeywords: String {
107125
108126struct SymbolInfo {
109127 let name : String
110- let kind : String
128+ let kind : ClassificationKeywords
111129 let startLine : Int
112130 let endLine : Int
113131 let content : String
132+ var extensions : [ SymbolContent ] = [ ]
114133}
115134
116135import SwiftSyntax
@@ -133,58 +152,57 @@ class DeclarationCollector: SyntaxVisitor {
133152// }
134153
135154 override func visit( _ node: ClassDeclSyntax ) -> SyntaxVisitorContinueKind {
136- recordSymbol ( name: node. name. text, kind: ClassificationKeywords . classWord. rawValue , node: node)
155+ recordSymbol ( name: node. name. text, kind: ClassificationKeywords . classWord, node: node)
137156 return . skipChildren
138157 }
139158
140159 override func visit( _ node: StructDeclSyntax ) -> SyntaxVisitorContinueKind {
141- recordSymbol ( name: node. name. text, kind: ClassificationKeywords . structWord. rawValue , node: node)
160+ recordSymbol ( name: node. name. text, kind: ClassificationKeywords . structWord, node: node)
142161 return . skipChildren
143162 }
144163
145164 override func visit( _ node: EnumDeclSyntax ) -> SyntaxVisitorContinueKind {
146- recordSymbol ( name: node. name. text, kind: ClassificationKeywords . enumWord. rawValue , node: node)
165+ recordSymbol ( name: node. name. text, kind: ClassificationKeywords . enumWord, node: node)
147166 return . skipChildren
148167 }
149168
150169 override func visit( _ node: ProtocolDeclSyntax ) -> SyntaxVisitorContinueKind {
151- recordSymbol ( name: node. name. text, kind: ClassificationKeywords . protocolWord. rawValue , node: node)
170+ recordSymbol ( name: node. name. text, kind: ClassificationKeywords . protocolWord, node: node)
152171 return . skipChildren
153172 }
154173
155174 override func visit( _ node: ActorDeclSyntax ) -> SyntaxVisitorContinueKind {
156- recordSymbol ( name: node. name. text, kind: ClassificationKeywords . actorWord. rawValue , node: node)
175+ recordSymbol ( name: node. name. text, kind: ClassificationKeywords . actorWord, node: node)
157176 return . skipChildren
158177 }
159178
160179 override func visit( _ node: FunctionDeclSyntax ) -> SyntaxVisitorContinueKind {
161- recordSymbol ( name: node. name. text, kind: ClassificationKeywords . funcWord. rawValue , node: node)
180+ recordSymbol ( name: node. name. text, kind: ClassificationKeywords . funcWord, node: node)
162181 return . skipChildren
163182 }
164183
165184 override func visit( _ node: VariableDeclSyntax ) -> SyntaxVisitorContinueKind {
166185 guard let binding = node. bindings. first,
167- let pattern = binding. pattern. as ( IdentifierPatternSyntax . self) else {
186+ let pattern = binding. pattern. as ( IdentifierPatternSyntax . self) ,
187+ let keyword: ClassificationKeywords = ClassificationKeywords ( rawValue: node. bindingSpecifier. text) else {
168188 return . skipChildren
169189 }
170-
171- let keyword = node. bindingSpecifier. text // "let" or "var"
172190 recordSymbol ( name: pattern. identifier. text, kind: keyword, node: node)
173191 return . skipChildren
174192 }
175193
176194 override func visit( _ node: ExtensionDeclSyntax ) -> SyntaxVisitorContinueKind {
177195 let name = node. extendedType. trimmedDescription
178- recordSymbol ( name: name, kind: ClassificationKeywords . extensionWord. rawValue , node: node)
196+ recordSymbol ( name: name, kind: ClassificationKeywords . extensionWord, node: node)
179197 return . skipChildren
180198 }
181199
182200 override func visit( _ node: TypeAliasDeclSyntax ) -> SyntaxVisitorContinueKind {
183- recordSymbol ( name: node. name. text, kind: ClassificationKeywords . typealiasWord. rawValue , node: node)
201+ recordSymbol ( name: node. name. text, kind: ClassificationKeywords . typealiasWord, node: node)
184202 return . skipChildren
185203 }
186204
187- private func recordSymbol( name: String , kind: String , node: SyntaxProtocol ) {
205+ private func recordSymbol( name: String , kind: ClassificationKeywords , node: SyntaxProtocol ) {
188206 let startLoc = sourceLocationConverter. location ( for: node. positionAfterSkippingLeadingTrivia)
189207 let endLoc = sourceLocationConverter. location ( for: node. endPositionBeforeTrailingTrivia)
190208 let startLineIndex = startLoc. line - 1
0 commit comments