Sources/SwiftCodeSanKit/Utils/Extensions/SyntaxExtensions.swift (1,210 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
protocol DeclProtocol {
var type: String { get }
var name: String { get }
var fullName: String { get }
var declType: DeclType { get }
var inheritedTypes: [String] { get }
func refTypes(with declMap: DeclMap, filterKey: String?) -> [String]
var refTypes: [String] { get }
var boundTypes: [String] { get }
var boundTypesAL: [String] { get } // Bound types for access levels
var accessLevel: String { get }
var isOverride: Bool { get }
var isExprOrStmt: Bool { get }
func declMetadatas(path: String, module: String, encloser: String, description: String, imports: [String]) -> [DeclMetadata]
}
extension DeclProtocol {
func declMetadatas(path: String, module: String, encloser: String, description: String, imports: [String]) -> [DeclMetadata] {
if let declSyntax = self as? DeclSyntax, let varSyntax = declSyntax.as(VariableDeclSyntax.self) {
return varSyntax.declMetadatas(path: path, module: module, encloser: encloser, description: description, imports: imports)
}
let val = DeclMetadata(path: path,
module: module,
imports: imports,
encloser: encloser,
name: name,
type: type,
fullName: fullName,
description: description,
declType: declType,
inheritedTypes: inheritedTypes,
boundTypes: boundTypes,
boundTypesAL: boundTypesAL,
isPublicOrOpen: accessLevel.isPublicOrOpen,
isOverride: isOverride,
used: false)
return [val]
}
func refTypes(with declMap: DeclMap, filterKey: String? = nil) -> [String] {
return refTypes.filter { declMap[$0] != nil || $0.contains(".") || $0.hasSuffix("Strings") || $0.hasSuffix("Images") }
}
}
extension Syntax: DeclProtocol {
var name: String {
return ""
}
var type: String {
return ""
}
var fullName: String {
return name
}
var accessLevel: String {
return ""
}
var isOverride: Bool {
return false
}
var isExprOrStmt: Bool {
return false
}
var declType: DeclType {
return .other
}
var inheritedTypes: [String] {
return []
}
var refTypes: [String] {
return boundTypesAL
}
var boundTypes: [String] {
return tokens.exprTokenList
}
var boundTypesAL: [String] {
return boundTypes
}
}
extension DeclSyntax: DeclProtocol {
var name: String {
if let d = self.as(FunctionDeclSyntax.self) {
return d.name
} else if let d = self.as(VariableDeclSyntax.self) {
return d.name
} else if let d = self.as(InitializerDeclSyntax.self) {
return d.name
} else if let d = self.as(SubscriptDeclSyntax.self) {
return d.name
} else if let d = self.as(ProtocolDeclSyntax.self) {
return d.name
} else if let d = self.as(ClassDeclSyntax.self) {
return d.name
} else if let d = self.as(ExtensionDeclSyntax.self) {
return d.name
} else if let d = self.as(StructDeclSyntax.self) {
return d.name
} else if let d = self.as(EnumDeclSyntax.self) {
return d.name
} else if let d = self.as(EnumCaseDeclSyntax.self) {
return d.name
} else if let d = self.as(TypealiasDeclSyntax.self) {
return d.name
} else if let d = self.as(AssociatedtypeDeclSyntax.self) {
return d.name
} else {
return ""
}
}
var type: String {
if let d = self.as(FunctionDeclSyntax.self) {
return d.type
} else if let d = self.as(SubscriptDeclSyntax.self) {
return d.type
} else if let d = self.as(VariableDeclSyntax.self) {
return d.type
}
return name
}
var fullName: String {
if let d = self.as(FunctionDeclSyntax.self) {
return d.fullName
} else if let d = self.as(VariableDeclSyntax.self) {
return d.fullName
} else if let d = self.as(InitializerDeclSyntax.self) {
return d.fullName
} else if let d = self.as(SubscriptDeclSyntax.self) {
return d.fullName
} else if let d = self.as(ProtocolDeclSyntax.self) {
return d.fullName
} else if let d = self.as(ClassDeclSyntax.self) {
return d.fullName
} else if let d = self.as(StructDeclSyntax.self) {
return d.fullName
} else if let d = self.as(EnumDeclSyntax.self) {
return d.fullName
} else if let d = self.as(ExtensionDeclSyntax.self) {
return d.fullName
} else if let d = self.as(EnumCaseDeclSyntax.self) {
return d.fullName
} else if let d = self.as(TypealiasDeclSyntax.self) {
return d.fullName
} else if let d = self.as(AssociatedtypeDeclSyntax.self) {
return d.fullName
}
return name
}
var declType: DeclType {
if let d = self.as(FunctionDeclSyntax.self) {
return d.declType
} else if let d = self.as(VariableDeclSyntax.self) {
return d.declType
} else if let d = self.as(InitializerDeclSyntax.self) {
return d.declType
} else if let d = self.as(SubscriptDeclSyntax.self) {
return d.declType
} else if let d = self.as(ProtocolDeclSyntax.self) {
return d.declType
} else if let d = self.as(ClassDeclSyntax.self) {
return d.declType
} else if let d = self.as(ExtensionDeclSyntax.self) {
return d.declType
} else if let d = self.as(StructDeclSyntax.self) {
return d.declType
} else if let d = self.as(EnumDeclSyntax.self) {
return d.declType
} else if let d = self.as(EnumCaseDeclSyntax.self) {
return d.declType
} else if let d = self.as(TypealiasDeclSyntax.self) {
return d.declType
} else if let d = self.as(AssociatedtypeDeclSyntax.self) {
return d.declType
}
return .other
}
var inheritedTypes: [String] {
if let d = self.as(ProtocolDeclSyntax.self) {
return d.inheritedTypes
} else if let d = self.as(ClassDeclSyntax.self) {
return d.inheritedTypes
} else if let d = self.as(ExtensionDeclSyntax.self) {
return d.inheritedTypes
} else if let d = self.as(StructDeclSyntax.self) {
return d.inheritedTypes
} else if let d = self.as(EnumDeclSyntax.self) {
return d.inheritedTypes
} else if let d = self.as(TypealiasDeclSyntax.self) {
return d.inheritedTypes
} else if let d = self.as(AssociatedtypeDeclSyntax.self) {
return d.inheritedTypes
}
return []
}
func refTypes(with declMap: DeclMap, filterKey: String?) -> [String] {
var list = refTypes
if !declMap.isEmpty {
list = list.filter{declMap[$0] != nil}
}
return list
}
var refTypes: [String] {
if let d = self.as(FunctionDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(VariableDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(InitializerDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(SubscriptDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(ProtocolDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(ClassDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(ExtensionDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(StructDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(EnumDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(EnumCaseDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(TypealiasDeclSyntax.self) {
return d.refTypes
} else if let d = self.as(AssociatedtypeDeclSyntax.self) {
return d.refTypes
}
return []
}
var boundTypes: [String] {
if let d = self.as(FunctionDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(VariableDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(InitializerDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(SubscriptDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(ProtocolDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(ClassDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(ExtensionDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(StructDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(EnumDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(EnumCaseDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(TypealiasDeclSyntax.self) {
return d.boundTypes
} else if let d = self.as(AssociatedtypeDeclSyntax.self) {
return d.boundTypes
}
return []
}
var boundTypesAL: [String] {
if let d = self.as(FunctionDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(VariableDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(InitializerDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(SubscriptDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(ProtocolDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(ClassDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(ExtensionDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(StructDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(EnumDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(EnumCaseDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(TypealiasDeclSyntax.self) {
return d.boundTypesAL
} else if let d = self.as(AssociatedtypeDeclSyntax.self) {
return d.boundTypesAL
}
return []
}
var accessLevel: String {
if let d = self.as(FunctionDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(VariableDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(InitializerDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(SubscriptDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(ProtocolDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(ClassDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(ExtensionDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(StructDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(EnumDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(EnumCaseDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(TypealiasDeclSyntax.self) {
return d.accessLevel
} else if let d = self.as(AssociatedtypeDeclSyntax.self) {
return d.accessLevel
}
return ""
}
var isOverride: Bool {
if let d = self.as(FunctionDeclSyntax.self) {
return d.isOverride
} else if let d = self.as(VariableDeclSyntax.self) {
return d.isOverride
} else if let d = self.as(InitializerDeclSyntax.self) {
return d.isOverride
}
return false
}
var isExprOrStmt: Bool {
_syntaxNode.is(StmtSyntax.self) || _syntaxNode.is(ExprSyntax.self)
}
}
extension MemberDeclListItemSyntax: DeclProtocol {
var refTypes: [String] {
return decl.refTypes
}
var declType: DeclType {
return decl.declType
}
var inheritedTypes: [String] {
return decl.inheritedTypes
}
var boundTypes: [String] {
return decl.boundTypes
}
var boundTypesAL: [String] {
return decl.boundTypesAL
}
var accessLevel: String {
return decl.accessLevel
}
var isOverride: Bool {
return decl.isOverride
}
var isExprOrStmt: Bool {
return decl.isExprOrStmt
}
var name: String {
return decl.name
}
var type: String {
return decl.type
}
var fullName: String {
return decl.fullName
}
}
extension MemberDeclListSyntax: DeclProtocol {
var name: String {
return ""
}
var type: String {
return name
}
var fullName: String {
return name
}
var declType: DeclType {
return .other
}
var inheritedTypes: [String] {
return []
}
var accessLevel: String {
return ""
}
var isOverride: Bool {
return false
}
var isExprOrStmt: Bool {
return false
}
var boundTypes: [String] {
return self.map { $0.decl.boundTypes }.flatMap{$0}
}
var boundTypesAL: [String] {
return self.map { $0.decl.boundTypesAL }.flatMap{$0}
}
var refTypes: [String] {
return boundTypesAL
}
}
extension ProtocolDeclSyntax: DeclProtocol {
var fullName: String {
return name
}
var type: String {
return name
}
var isExprOrStmt: Bool {
return false
}
var isOverride: Bool {
return false
}
var name: String {
return identifier.text.raw
}
var accessLevel: String {
return self.modifiers?.acl ?? ""
}
var inheritedTypes: [String] {
return [inheritanceClause?.tokens.exprTokenList,
genericWhereClause?.tokens.exprTokenList,
].compactMap{$0}.flatMap{$0}.filter{$0 != name}
}
var boundTypes: [String] {
return inheritedTypes
}
var boundTypesAL: [String] {
return [boundTypes,
members.members.boundTypesAL,
].compactMap{$0}.flatMap{$0}
}
var refTypes: [String] {
return boundTypesAL
}
var declType: DeclType {
return .protocolType
}
var isPrivate: Bool {
return self.modifiers?.isPrivate ?? false
}
var attributesDescription: String {
self.attributes?.trimmedDescription ?? ""
}
var offset: Int64 {
return Int64(self.position.utf8Offset)
}
func annotationMetadata(with annotation: String) -> AnnotationMetadata? {
return leadingTrivia?.annotationMetadata(with: annotation)
}
}
extension ClassDeclSyntax: DeclProtocol {
var fullName: String {
return name
}
var type: String {
return name
}
var isExprOrStmt: Bool {
return false
}
var isOverride: Bool {
return false
}
var name: String {
return identifier.text.raw
}
var accessLevel: String {
return self.modifiers?.acl ?? ""
}
var declType: DeclType {
return .classType
}
var boundTypes: [String] {
return inheritedTypes
}
var boundTypesAL: [String] {
return boundTypes
}
var refTypes: [String] {
return [boundTypesAL,
members.members.boundTypesAL,
].compactMap{$0}.flatMap{$0}
}
var inheritedTypes: [String] {
return [genericParameterClause?.genericParameterList.tokens.exprTokenList,
genericWhereClause?.tokens.exprTokenList,
inheritanceClause?.tokens.exprTokenList
].compactMap{$0}.flatMap{$0}.filter{$0 != name}
}
var attributesDescription: String {
self.attributes?.trimmedDescription ?? ""
}
var offset: Int64 {
return Int64(self.position.utf8Offset)
}
func annotationMetadata(with annotation: String) -> AnnotationMetadata? {
return leadingTrivia?.annotationMetadata(with: annotation)
}
}
extension ExtensionDeclSyntax: DeclProtocol {
var fullName: String {
return extendedType.description.trimmed + "_" + inheritedTypes.joined()
}
var type: String {
return name
}
var isExprOrStmt: Bool {
return false
}
var isOverride: Bool {
return false
}
var name: String {
let str = extendedType.description.trimmed.raw
let comps = str.components(separatedBy: ".")
if let last = comps.last, !last.isEmpty {
return last
}
return str
}
var declType: DeclType {
return .extensionType
}
var accessLevel: String {
return self.modifiers?.acl ?? ""
}
var inheritedTypes: [String] {
return [inheritanceClause?.tokens.exprTokenList,
genericWhereClause?.tokens.exprTokenList,
].compactMap{$0}.flatMap{$0}.filter{$0 != name}
}
var boundTypes: [String] {
var ret = inheritedTypes
ret.append(name)
return ret
}
var boundTypesAL: [String] {
return [boundTypes,
members.members.boundTypesAL,
].compactMap{$0}.flatMap{$0}
}
var refTypes: [String] {
return boundTypesAL
}
func refTypes(with declMap: DeclMap, filterKey: String? = nil) -> [String] {
var list = [extendedType.tokens.exprTokenList,
refTypes
].compactMap{$0}.flatMap{$0}
if !declMap.isEmpty {
list = list.filter{declMap[$0] != nil}
}
return list
}
}
extension EnumCaseDeclSyntax: DeclProtocol {
var inheritedTypes: [String] {
return []
}
var type: String {
return name
}
var isExprOrStmt: Bool {
return false
}
var isOverride: Bool {
return false
}
var name: String {
let ret = elements.map{$0.identifier.text}.first ?? elements.description
return ret.raw
}
var fullName: String {
return self.elements.description
}
var accessLevel: String {
return self.modifiers?.acl ?? ""
}
var declType: DeclType {
return .enumCaseType
}
var boundTypes: [String] {
let list = elements.compactMap{$0.associatedValue?.parameterList.compactMap{$0.type?.tokens.exprTokenList}.flatMap{$0}}.flatMap{$0}
return list
}
var boundTypesAL: [String] {
return boundTypes
}
var refTypes: [String] {
return boundTypesAL
}
}
extension EnumDeclSyntax: DeclProtocol {
var fullName: String {
return name + "_" + inheritedTypes.joined()
}
var type: String {
return name
}
var isExprOrStmt: Bool {
return false
}
var isOverride: Bool {
return false
}
var attributesDescription: String {
self.attributes?.description.trimmed ?? ""
}
var name: String {
return identifier.text.trimmed.raw
}
var accessLevel: String {
return self.modifiers?.acl ?? ""
}
var declType: DeclType {
return .enumType
}
var inheritedTypes: [String] {
return [inheritanceClause?.tokens.exprTokenList,
genericParameters?.tokens.exprTokenList,
genericWhereClause?.tokens.exprTokenList
].compactMap{$0}.flatMap{$0}.filter{ $0 != name }
}
var boundTypes: [String] {
return inheritedTypes
}
var boundTypesAL: [String] {
return [boundTypes,
members.members.boundTypesAL
].compactMap{$0}.flatMap{$0}
}
var refTypes: [String] {
return boundTypesAL
}
}
extension StructDeclSyntax: DeclProtocol {
var fullName: String {
return name + "_" + inheritedTypes.joined()
}
var type: String {
return name
}
var isExprOrStmt: Bool {
return false
}
var isOverride: Bool {
return false
}
var attributesDescription: String {
self.attributes?.description.trimmed ?? ""
}
var name: String {
return identifier.text.trimmed.raw
}
var declType: DeclType {
return .structType
}
var accessLevel: String {
return self.modifiers?.acl ?? ""
}
var inheritedTypes: [String] {
return [inheritanceClause?.tokens.exprTokenList,
genericParameterClause?.tokens.exprTokenList,
genericWhereClause?.tokens.exprTokenList,
].compactMap{$0}.flatMap{$0}.filter{ $0 != name }
}
var boundTypes: [String] {
return inheritedTypes
}
var boundTypesAL: [String] {
return boundTypes
}
var refTypes: [String] {
return [boundTypesAL,
members.members.boundTypesAL,
].compactMap{$0}.flatMap{$0}
}
}
extension AssociatedtypeDeclSyntax: DeclProtocol {
var isExprOrStmt: Bool {
return false
}
var isOverride: Bool {
return false
}
var type: String {
return name
}
var name: String {
return identifier.text.trimmed.raw
}
var fullName: String {
return name + "_" + boundTypes.joined()
}
var declType: DeclType {
return .patType
}
var accessLevel: String {
return self.modifiers?.acl ?? ""
}
var inheritedTypes: [String] {
return [inheritanceClause?.tokens.exprTokenList,
genericWhereClause?.tokens.exprTokenList,
].compactMap{$0}.flatMap{$0}.filter{$0 != name}
}
var boundTypes: [String] {
return [inheritedTypes,
initializer?.value.tokens.exprTokenList.filter{$0 != name}
].compactMap{$0}.flatMap{$0}
}
var boundTypesAL: [String] {
return boundTypes
}
var refTypes: [String] {
return boundTypesAL
}
}
extension TypealiasDeclSyntax: DeclProtocol {
var isExprOrStmt: Bool {
return false
}
var isOverride: Bool {
return false
}
var type: String {
return name
}
var name: String {
return identifier.text.trimmed.raw
}
var fullName: String {
return name + "_" + boundTypes.joined()
}
var declType: DeclType {
return .typealiasType
}
var accessLevel: String {
return self.modifiers?.acl ?? ""
}
var inheritedTypes: [String] {
return [genericParameterClause?.tokens.exprTokenList,
genericWhereClause?.tokens.exprTokenList,
].compactMap{$0}.flatMap{$0}.filter{$0 != name}
}
var boundTypes: [String] {
return [inheritedTypes,
initializer?.value.tokens.exprTokenList.filter{$0 != name}
].compactMap{$0}.flatMap{$0}
}
var boundTypesAL: [String] {
return boundTypes
}
var refTypes: [String] {
return boundTypesAL
}
}
extension PatternBindingSyntax {
var type: String {
if let t = typeAnnotation?.type.description.trimmed {
return t
}
if let val = initializer?.value {
if let expr = val.as(FunctionCallExprSyntax.self) {
return expr.calledExpression.description.trimmed
} else if let expr = val.as(ExprSyntax.self) {
return expr.description.trimmed
}
}
return .unknownVal
}
func boundTypes(isTransparent: Bool) -> [String] {
var list = [String]()
if let bound = typeAnnotation?.type.tokens.exprTokenList {
list.append(contentsOf: bound)
}
if let val = initializer?.value {
if let expr = val.as(FunctionCallExprSyntax.self) {
let exprList = [
expr.calledExpression.tokens.exprTokenList,
expr.argumentList.map{$0.expression.tokens.exprTokenList}.flatMap{$0}
].flatMap{$0}
list.append(contentsOf: exprList)
} else if let expr = val.as(ExprSyntax.self) {
list.append(contentsOf: expr.tokens.exprTokenList)
}
}
if isTransparent {
if let bodyTokens = accessor?.tokens.exprTokenList {
list.append(contentsOf: bodyTokens)
}
}
return list
}
}
extension VariableDeclSyntax: DeclProtocol {
func declMetadatas(path: String, module: String, encloser: String, description: String, imports: [String]) -> [DeclMetadata] {
var list = [DeclMetadata]()
for binding in bindings {
if let idpattern = binding.pattern.as(IdentifierPatternSyntax.self) {
let id = idpattern.identifier.text
if id == "_" { continue }
let ty = binding.type
let full = id + "_" + ty
let bound = binding.boundTypes(isTransparent: isTransparent)
let val = DeclMetadata(path: path,
module: module,
imports: imports,
encloser: encloser,
name: id,
type: ty,
fullName: full,
description: description,
declType: declType,
inheritedTypes: inheritedTypes,
boundTypes: bound,
boundTypesAL: bound,
isPublicOrOpen: accessLevel.isPublicOrOpen,
isOverride: isOverride,
used: false)
list.append(val)
} else if let tuple = binding.pattern.as(TuplePatternSyntax.self) {
for el in tuple.elements {
if let idpattern = el.pattern.as(IdentifierPatternSyntax.self) {
let id = idpattern.identifier.text
if id == "_" { continue }
let ty = binding.type
let full = id + "_" + ty
let bound = binding.boundTypes(isTransparent: isTransparent)
let val = DeclMetadata(path: path,
module: module,
imports: imports,
encloser: encloser,
name: id,
type: ty,
fullName: full,
description: description,
declType: declType,
inheritedTypes: inheritedTypes,
boundTypes: bound,
boundTypesAL: bound,
isPublicOrOpen: accessLevel.isPublicOrOpen,
isOverride: isOverride,
used: false)
list.append(val)
}
}
}
}
return list
}
var isTransparent: Bool {
return attributesDescription.contains(String.transparent)
}
var name: String {
let ret = bindings.compactMap { $0.pattern.description.trimmed }.joined().raw
return ret
}
var inheritedTypes: [String] {
return []
}
var isExprOrStmt: Bool {
return false
}
var fullName: String {
return name + "_" + type
}
var declType: DeclType {
return .varType
}
var accessLevel: String {
return self.modifiers?.acl ?? ""
}
var isOverride: Bool {
return modifiers?.isOverride ?? false
}
var attributesDescription: String {
return attributes?.trimmedDescription ?? ""
}
var type: String {
return bindings.first?.type ?? ""
}
var boundTypes: [String] {
var list = [String]()
for b in bindings {
list.append(contentsOf: b.boundTypes(isTransparent: isTransparent))
}
if let attrs = attributes?.tokens.exprTokenList {
list.append(contentsOf: attrs)
}
return list.filter{$0 != name}
}
var boundTypesAL: [String] {
return boundTypes
}
var refTypes: [String] {
let ret = [boundTypesAL,
bindings.compactMap{$0.accessor?.tokens.exprTokenList}.flatMap{$0}
].compactMap{$0}.flatMap{$0}
return ret
}
}
extension FunctionDeclSyntax: DeclProtocol {
var name: String {
return self.identifier.description.trimmed.raw
}
var type: String {
return signature.output?.returnType.description.trimmed ?? ""
}
var fullName: String {
return name + signature.description.trimmed
}
var declType: DeclType {
if self.identifier.tokenKind == .spacedBinaryOperator(self.identifier.text) {
return .operatorType
}
return .funcType
}
var accessLevel: String {
return self.modifiers?.acl ?? ""
}
var isOverride: Bool {
return modifiers?.isOverride ?? false
}
var attributesDescription: String {
return attributes?.trimmedDescription ?? ""
}
var inheritedTypes: [String] {
return []
}
var isExprOrStmt: Bool {
return false
}
var boundTypes: [String] {
let genericParamTypes = genericParameterClause?.genericParameterList.tokens.exprTokenList
let genericWhereTypes = genericWhereClause?.tokens.exprTokenList
let paramTypes = signature.input.parameterList.compactMap{$0.type?.tokens.exprTokenList}.flatMap{$0}
let paramVals = signature.input.parameterList.compactMap{$0.defaultArgument?.value.tokens.exprTokenList}.flatMap{$0}
let returnTypes = signature.output?.returnType.tokens.exprTokenList
let attrs = attributes?.tokens.exprTokenList // e.g. @FunctionBuilder
var list = [genericParamTypes, genericWhereTypes, paramTypes, paramVals, returnTypes, attrs].compactMap{$0}.flatMap{$0}
if attributesDescription.contains(String.transparent) {
if let bodyTokens = body?.tokens.exprTokenList {
list.append(contentsOf: bodyTokens)
}
}
return list.filter{$0 != name}
}
var boundTypesAL: [String] {
return boundTypes
}
var refTypes: [String] {
return [boundTypesAL,
body?.tokens.exprTokenList
].compactMap{$0}.flatMap{$0}
}
}
extension InitializerDeclSyntax: DeclProtocol {
var name: String {
return "init"
}
var type: String {
return name
}
var fullName: String {
return name + "_" + parameters.description.trimmed
}
var declType: DeclType {
return .initType
}
var isOverride: Bool {
return modifiers?.isOverride ?? false
}
var attributesDescription: String {
return attributes?.trimmedDescription ?? ""
}
var accessLevel: String {
return modifiers?.acl ?? ""
}
var boundTypes: [String] {
let genericParamTypes = genericParameterClause?.genericParameterList.tokens.exprTokenList
let genericWhereTypes = genericWhereClause?.tokens.exprTokenList
var paramList = [String]()
for param in parameters.parameterList {
if let pval = param.defaultArgument?.value {
if let accessed = pval.as(MemberAccessExprSyntax.self), let base = accessed.base {
paramList.append(accessed.description.trimmed)
paramList.append(contentsOf: base.tokens.exprTokenList)
} else {
paramList.append(contentsOf: pval.tokens.exprTokenList)
}
}
if let ptypes = param.type?.tokens.exprTokenList {
paramList.append(contentsOf: ptypes)
}
}
var list = [genericParamTypes, genericWhereTypes, paramList].compactMap{$0}.flatMap{$0}
// @_transparent on public or @usableFromInline functions require all types in sig and body to be public
if attributesDescription.contains(String.transparent) {
if let bodyTokens = body?.tokens.exprTokenList {
list.append(contentsOf: bodyTokens)
}
}
return list.filter{$0 != name}
}
var boundTypesAL: [String] {
return boundTypes
}
var refTypes: [String] {
return [boundTypesAL,
body?.tokens.exprTokenList
].compactMap{$0}.flatMap{$0}
}
var inheritedTypes: [String] {
return []
}
var isExprOrStmt: Bool {
return false
}
func isRequired(with declType: DeclType) -> Bool {
if declType == .protocolType {
return true
} else if declType == .classType {
if let modifiers = self.modifiers {
if modifiers.isConvenience {
return false
}
return modifiers.isRequired
}
}
return false
}
}
extension SubscriptDeclSyntax: DeclProtocol {
var fullName: String {
return name + "_" + result.returnType.description.trimmed
}
var name: String {
return self.subscriptKeyword.text
}
var declType: DeclType {
return .subscriptType
}
var accessLevel: String {
return modifiers?.acl ?? ""
}
var inheritedTypes: [String] {
return []
}
var isExprOrStmt: Bool {
return false
}
var isOverride: Bool {
return false
}
var type: String {
return result.returnType.description.trimmed
}
var boundTypes: [String] {
return [result.returnType.tokens.exprTokenList,
genericParameterClause?.genericParameterList.tokens.exprTokenList,
genericWhereClause?.tokens.exprTokenList,
attributes?.tokens.exprTokenList,
].compactMap{$0}.flatMap{$0}.filter {$0 != name }
}
var boundTypesAL: [String] {
return boundTypes
}
var refTypes: [String] {
return [boundTypesAL,
accessor?.tokens.exprTokenList
].compactMap{$0}.flatMap{$0}
}
}
// MARK -
extension AttributeListSyntax {
var trimmedDescription: String? {
return self.withoutTrivia().description.trimmingCharacters(in: .whitespacesAndNewlines)
}
}
extension ModifierListSyntax {
var acl: String {
for modifier in self {
for token in modifier.tokens {
switch token.tokenKind {
case .publicKeyword, .internalKeyword, .privateKeyword, .fileprivateKeyword:
return token.text
default:
// For some reason openKeyword option is not available in TokenKind so need to address separately
if token.text == String.open {
return token.text
}
}
}
}
return ""
}
var isStatic: Bool {
return self.tokens.filter {$0.tokenKind == .staticKeyword }.count > 0
}
var isRequired: Bool {
return self.tokens.filter {$0.text == String.required }.count > 0
}
var isConvenience: Bool {
return self.tokens.filter {$0.text == String.convenience }.count > 0
}
var isOverride: Bool {
return self.tokens.filter {$0.text == String.override }.count > 0
}
var isFinal: Bool {
return self.tokens.filter {$0.text == String.final }.count > 0
}
var isPrivate: Bool {
return self.tokens.filter {$0.tokenKind == .privateKeyword || $0.tokenKind == .fileprivateKeyword }.count > 0
}
var isPublic: Bool {
return self.tokens.filter {$0.tokenKind == .publicKeyword }.count > 0
}
var isOpen: Bool {
return self.tokens.filter {$0.text == String.open }.count > 0
}
}
extension Trivia {
// This parses arguments in annotation which can be used to override certain types.
//
// E.g. given /// @mockable(typealias: T = Any; U = AnyObject), it returns
// a dictionary: [T: Any, U: AnyObject] which will be used to override inhertied types
// of typealias decls for T and U.
private func metadata(with annotation: String, in val: String) -> AnnotationMetadata? {
if val.contains(annotation) {
let comps = val.components(separatedBy: annotation)
var ret = AnnotationMetadata()
if var argsStr = comps.last, !argsStr.isEmpty {
if argsStr.hasPrefix("(") {
argsStr.removeFirst()
}
if argsStr.hasSuffix(")") {
argsStr.removeLast()
}
if argsStr.contains(String.typealiasColon), let subStr = argsStr.components(separatedBy: String.typealiasColon).last, !subStr.isEmpty {
ret.typeAliases = subStr.arguments(with: .annotationArgDelimiter)
}
if argsStr.contains(String.moduleColon), let subStr = argsStr.components(separatedBy: String.moduleColon).last, !subStr.isEmpty {
let val = subStr.arguments(with: .annotationArgDelimiter)
ret.module = val?[.prefix]
}
if argsStr.contains(String.rxColon), let subStr = argsStr.components(separatedBy: String.rxColon).last, !subStr.isEmpty {
ret.varTypes = subStr.arguments(with: .annotationArgDelimiter)
}
if argsStr.contains(String.varColon), let subStr = argsStr.components(separatedBy: String.varColon).last, !subStr.isEmpty {
if let val = subStr.arguments(with: .annotationArgDelimiter) {
if ret.varTypes == nil {
ret.varTypes = val
} else {
ret.varTypes?.merge(val, uniquingKeysWith: {$1})
}
}
}
}
return ret
}
return nil
}
// Looks up an annotation (e.g. /// @mockable) and its arguments if any.
// See metadata(with:, in:) for more info on the annotation arguments.
func annotationMetadata(with annotation: String) -> AnnotationMetadata? {
guard !annotation.isEmpty else { return nil }
var ret: AnnotationMetadata?
for i in 0..<count {
let trivia = self[i]
switch trivia {
case .docLineComment(let val):
ret = metadata(with: annotation, in: val)
if ret != nil {
return ret
}
case .docBlockComment(let val):
ret = metadata(with: annotation, in: val)
if ret != nil {
return ret
}
default:
continue
}
}
return nil
}
}
extension TokenSyntax {
var stringToken: String? {
if text == "self" || text == "Self" || text == "super" || text == "nil" ||
text == "as" || text == "true" || text == "false" || text == "AnyObject" || text == "Any" {
return nil
}
let startsWithLetter = text.first?.isLetter ?? false
let validFirstChar = text.first == "_" || startsWithLetter
if (validFirstChar && (text.isAlphanumeric || text.contains("_"))) ||
tokenKind == .spacedBinaryOperator(text) {
return text
}
return nil
}
var exprToken: String? {
if tokenKind != .stringQuote,
tokenKind != .stringSegment(text),
tokenKind != .spacedBinaryOperator(text),
tokenKind != .initKeyword {
return stringToken
}
return nil
}
func filteredToken(with suffix: String) -> String? {
if text.hasSuffix(suffix) {
return String(text.dropLast(suffix.count))
}
return nil
}
}
extension TokenSequence {
var tokenList: [String] {
return self.compactMap { $0.stringToken }
}
var exprTokenList: [String] {
return self.compactMap { $0.exprToken }
}
}