Sources/SwiftCodeSanKit/FileParsers/DeclParser.swift (148 lines of code) (raw):

// // Copyright (c) 2018. Uber Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // import Foundation import SwiftSyntax import SwiftSyntaxParser public class DeclParser { public init() {} func scanAndMapDecls(fileToModuleMap: [String: String], topDeclsOnly: Bool, whitelist: Whitelist?) -> DeclMap { var allDeclMap = DeclMap() scanDecls(fileToModuleMap: fileToModuleMap, topDeclsOnly: topDeclsOnly, whitelist: whitelist) { (filepath, subResults) in for (k, decls) in subResults { if allDeclMap[k] == nil { allDeclMap[k] = [] } for decl in decls { if allDeclMap[k]?.contains(decl) ?? false { // Already added, so do nothing } else { allDeclMap[k]?.append(decl) } } } } return allDeclMap } func scanAndMapDecls(fileToModuleMap: [String: String], topDeclsOnly: Bool) -> DeclMap { return scanAndMapDecls(fileToModuleMap: fileToModuleMap, topDeclsOnly: topDeclsOnly, whitelist: nil) } func scanDecls(fileToModuleMap: [String: String], topDeclsOnly: Bool, completion: @escaping (String, DeclMap) -> ()) { scan(fileToModuleMap) { (path: String, module: String, lock: NSLock?) in self.visitSrc(path: path, module: module, topDeclsOnly: topDeclsOnly, whitelist: nil, lock: lock, completion: completion) } } func scanDecls(fileToModuleMap: [String: String], topDeclsOnly: Bool, whitelist: Whitelist?, completion: @escaping (String, DeclMap) -> ()) { scan(fileToModuleMap) { (path: String, module: String, lock: NSLock?) in self.visitSrc(path: path, module: module, topDeclsOnly: topDeclsOnly, whitelist: whitelist, lock: lock, completion: completion) } } var wpaths = 0 var npaths = 0 private func visitSrc(path: String, module: String?, topDeclsOnly: Bool, whitelist: Whitelist?, lock: NSLock?, completion: @escaping (String, DeclMap) -> ()) { do { let node = try SyntaxParser.parse(path) let whitelistPath = FileManager.modifiedWithin(whitelist?.thresholdDays, at: path) if whitelistPath { wpaths += 1 } npaths += 1 let visitor = DeclVisitor(path, module: module, topDeclsOnly: topDeclsOnly, whitelistPath: whitelistPath, whitelist: whitelist) visitor.walk(node) lock?.lock() defer {lock?.unlock()} completion(path, visitor.declMap) } catch { fatalError(error.localizedDescription) } } func checkRefs(fileToModuleMap: [String: String], declMap: DeclMap, completion: @escaping (String, Set<String>, [String]) -> ()) { scan(fileToModuleMap) { (path: String, module: String, lock: NSLock?) in self.referenceSrc(path: path, module: module, declMap: declMap, lock: lock, completion: completion) } } private func referenceSrc(path: String, module: String, declMap: DeclMap, lock: NSLock?, completion: @escaping (String, Set<String>, [String]) -> ()) { do { let node = try SyntaxParser.parse(path) let visitor = RefChecker(path, module: module, declMap: declMap) visitor.walk(node) lock?.lock() completion(path, visitor.refs, visitor.imports) lock?.unlock() } catch { fatalError(error.localizedDescription) } } // MARK - input is dirs or filepaths func scanDecls(paths: [String], isDirs: Bool, topDeclsOnly: Bool, pathToModules: [String: String], whitelist: Whitelist?, completion: @escaping (String, DeclMap) -> ()) { if isDirs { scan(dirs: paths) { (path: String, lock: NSLock?) in self.visitSrc(path: path, module: pathToModules[path], topDeclsOnly: topDeclsOnly, whitelist: whitelist, lock: lock, completion: completion) } } else { scan(paths) { (path: String, lock: NSLock?) in self.visitSrc(path: path, module: pathToModules[path], topDeclsOnly: topDeclsOnly, whitelist: whitelist, lock: lock, completion: completion) } } } func checkRefs(paths: [String], isDirs: Bool, pathToModules: [String: String], declMap: DeclMap, completion: @escaping (String, Set<String>, [String]) -> ()) { if isDirs { scan(dirs: paths) { (path: String, lock: NSLock?) in self.referenceSrc(path: path, module: pathToModules[path] ?? "", declMap: declMap, lock: lock, completion: completion) } } else { scan(paths) { (path: String, lock: NSLock?) in self.referenceSrc(path: path, module: pathToModules[path] ?? "", declMap: declMap, lock: lock, completion: completion) } } } }