Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct the throws clause in the closure within template logic to support TypedThrow. #262

Merged
merged 30 commits into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
199c2ef
Update swift-syntax to 600.0.0-prerelease
fummicc1 Jun 30, 2024
aa0e097
Resolve warnings for SwiftSyntax600
fummicc1 Jun 30, 2024
2e7259b
Update for tests
fummicc1 Jun 30, 2024
725c67d
update to support typed-throw
fummicc1 Jun 30, 2024
7f7028a
Update Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift
fummicc1 Aug 3, 2024
e3a2da8
Read accessor and omit setCallCount if protocol has no setter
sidepelican Oct 25, 2024
2a7a57d
Remove unnecessary static var handling
sidepelican Oct 25, 2024
96add24
Support get async and get throws property accessor
sidepelican Oct 25, 2024
72a125d
small rename and remove unused code
sidepelican Oct 25, 2024
0194530
generate initialize for computed var
sidepelican Oct 25, 2024
3acc4a7
computed getter handles with the same way of method
sidepelican Oct 25, 2024
c28c027
remove deprecated method
sidepelican Oct 25, 2024
0028467
Add test for throwing never
sidepelican Oct 25, 2024
802bed7
small formatting
sidepelican Oct 25, 2024
ee6da9a
Merge remote-tracking branch 'origin/master' into feature/issue-261-t…
fummicc1 Oct 26, 2024
c011048
Define FunctionSuffixClause.
fummicc1 Oct 26, 2024
62cbd3c
Change swift-syntax organization from apple to swiftlang
fummicc1 Oct 26, 2024
909d26e
Define FunctionSuffixClause
fummicc1 Oct 26, 2024
75a0f36
Update TestCase
fummicc1 Oct 26, 2024
bac0c69
refactoring
fummicc1 Oct 26, 2024
f4406dd
Merge branch 'property_accessor' into feature/issue-261-typed-throw
fummicc1 Oct 26, 2024
fa5ccbb
Merge remote-tracking branch 'origin/master' into feature/issue-261-t…
fummicc1 Oct 26, 2024
c004716
fix: remove unused string token.
fummicc1 Oct 26, 2024
de89895
Fix for typed throws
fummicc1 Oct 26, 2024
1b1de5d
rename argument for applyThrowingTemplate method. Add doc comment
fummicc1 Oct 26, 2024
f112110
Avoid to expose special parameter in a common method.
fummicc1 Oct 27, 2024
71d6920
Update TestFixture
fummicc1 Oct 27, 2024
733771e
Keep applyThrowingTemplate nullable to consider trivia.
fummicc1 Oct 27, 2024
be998e1
Refactor template logic for closure's suffix.
fummicc1 Oct 27, 2024
4a3a54a
Refactor function's suffix logic.
fummicc1 Oct 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
sidepelican marked this conversation as resolved.
Show resolved Hide resolved
"location" : "https://github.com/swiftlang/swift-syntax.git",
"state" : {
"revision" : "0687f71944021d616d34d922343dcef086855920",
"version" : "600.0.1"
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let package = Package(
.library(name: "MockoloFramework", targets: ["MockoloFramework"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-syntax.git", from: "600.0.1"),
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.1"),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.5.0"),
],
targets: [
Expand Down
4 changes: 2 additions & 2 deletions Sources/MockoloFramework/Models/ArgumentsHistoryModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ final class ArgumentsHistoryModel: Model {
var name: String
var type: SwiftType
var offset: Int64 = .max
let suffix: String
let suffix: FunctionSuffixClause?
let capturableParamNames: [String]
let capturableParamTypes: [SwiftType]
let isHistoryAnnotated: Bool
Expand All @@ -13,7 +13,7 @@ final class ArgumentsHistoryModel: Model {
return .argumentsHistory
}

init?(name: String, genericTypeParams: [ParamModel], params: [ParamModel], isHistoryAnnotated: Bool, suffix: String) {
init?(name: String, genericTypeParams: [ParamModel], params: [ParamModel], isHistoryAnnotated: Bool, suffix: FunctionSuffixClause?) {
// Value contains closure is not supported.
let capturables = params.filter { !$0.type.hasClosure && !$0.type.isEscaping && !$0.type.isAutoclosure }
guard !capturables.isEmpty else {
Expand Down
4 changes: 2 additions & 2 deletions Sources/MockoloFramework/Models/ClosureModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ final class ClosureModel: Model {
let genericTypeNames: [String]
let paramNames: [String]
let paramTypes: [SwiftType]
let suffix: String
let suffix: FunctionSuffixClause?

var modelType: ModelType {
return .closure
}


init(name: String, genericTypeParams: [ParamModel], paramNames: [String], paramTypes: [SwiftType], suffix: String, returnType: SwiftType, encloser: String) {
init(name: String, genericTypeParams: [ParamModel], paramNames: [String], paramTypes: [SwiftType], suffix: FunctionSuffixClause?, returnType: SwiftType, encloser: String) {
self.name = name + .handlerSuffix
self.suffix = suffix
let genericTypeNameList = genericTypeParams.map(\.name)
Expand Down
46 changes: 42 additions & 4 deletions Sources/MockoloFramework/Models/MethodModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ final class MethodModel: Model {
var modelDescription: String? = nil
var isStatic: Bool
let shouldOverride: Bool
let suffix: String
let suffix: FunctionSuffixClause?
let kind: MethodKind
let funcsWithArgsHistory: [String]
let customModifiers: [String : Modifier]
Expand Down Expand Up @@ -167,8 +167,8 @@ final class MethodModel: Model {
genericTypeParams: [ParamModel],
genericWhereClause: String?,
params: [ParamModel],
throwsOrRethrows: String?,
asyncOrReasync: String?,
throwsOrRethrows: FunctionThrowsSuffix?,
asyncOrReasync: FunctionAsyncSuffix?,
isStatic: Bool,
offset: Int64,
length: Int64,
Expand All @@ -178,7 +178,10 @@ final class MethodModel: Model {
processed: Bool) {
self.name = name.trimmingCharacters(in: .whitespaces)
self.type = SwiftType(typeName.trimmingCharacters(in: .whitespaces))
self.suffix = [asyncOrReasync, throwsOrRethrows].compactMap { $0 }.joined(separator: " ")
self.suffix = FunctionSuffixClause(
throwsSuffix: throwsOrRethrows,
asyncSuffix: asyncOrReasync
)
self.offset = offset
self.length = length
self.kind = kind
Expand Down Expand Up @@ -243,3 +246,38 @@ final class MethodModel: Model {
return result
}
}

/// throws, rethrows
///
/// if throws clause has a type information, the associated value `type` is not `nil`.
struct FunctionThrowsSuffix {
let isRethrows: Bool
let type: String?
}

/// async, reasync
struct FunctionAsyncSuffix {
var isReasync: Bool

var text: String {
isReasync ? String.reasync : String.async
}
}

/// Function Suffix Clause such as async / throws.
///
/// Since the support of typed throw, it is necessary to prepare a type that represents suffix in place of String type
/// due to the swift syntax's complexity.
struct FunctionSuffixClause {
var throwsSuffix: FunctionThrowsSuffix?
var asyncSuffix: FunctionAsyncSuffix?


init?(throwsSuffix: FunctionThrowsSuffix? = nil, asyncSuffix: FunctionAsyncSuffix? = nil) {
if throwsSuffix == nil, asyncSuffix == nil {
return nil
}
self.throwsSuffix = throwsSuffix
self.asyncSuffix = asyncSuffix
}
}
57 changes: 37 additions & 20 deletions Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -423,24 +423,33 @@ extension FunctionDeclSyntax {
let params = self.signature.parameterClause.parameters.compactMap { $0.model(inInit: false, declType: declType) }
let genericTypeParams = self.genericParameterClause?.parameters.compactMap { $0.model(inInit: false) } ?? []
let genericWhereClause = self.genericWhereClause?.description

let funcmodel = MethodModel(name: self.name.description,
typeName: self.signature.returnClause?.type.description ?? "",
kind: .funcKind,
encloserType: declType,
acl: acl,
genericTypeParams: genericTypeParams,
genericWhereClause: genericWhereClause,
params: params,
throwsOrRethrows: self.signature.effectSpecifiers?.throwsClause?.throwsSpecifier.text,
asyncOrReasync: self.signature.effectSpecifiers?.asyncSpecifier?.text,
isStatic: isStatic,
offset: self.offset,
length: self.length,
funcsWithArgsHistory: funcsWithArgsHistory ?? [],
customModifiers: customModifiers ?? [:],
modelDescription: self.description,
processed: processed)
let asyncSpecifier = self.signature.effectSpecifiers?.asyncSpecifier
let throwsClause = self.signature.effectSpecifiers?.throwsClause

let funcmodel = MethodModel(
name: self.name.description,
typeName: self.signature.returnClause?.type.description ?? "",
kind: .funcKind,
encloserType: declType,
acl: acl,
genericTypeParams: genericTypeParams,
genericWhereClause: genericWhereClause,
params: params,
throwsOrRethrows: throwsClause != nil ? FunctionThrowsSuffix(
isRethrows: throwsClause!.throwsSpecifier.text == String.rethrows,
type: throwsClause!.type?.description
) : nil,
asyncOrReasync: asyncSpecifier != nil ? FunctionAsyncSuffix(
isReasync: asyncSpecifier!.text == String.rethrows
) : nil,
isStatic: isStatic,
offset: self.offset,
length: self.length,
funcsWithArgsHistory: funcsWithArgsHistory ?? [],
customModifiers: customModifiers ?? [:],
modelDescription: self.description,
processed: processed
)
return funcmodel
}
}
Expand All @@ -464,6 +473,8 @@ extension InitializerDeclSyntax {
let params = self.signature.parameterClause.parameters.compactMap { $0.model(inInit: true, declType: declType) }
let genericTypeParams = self.genericParameterClause?.parameters.compactMap { $0.model(inInit: true) } ?? []
let genericWhereClause = self.genericWhereClause?.description
let asyncSpecifier = self.signature.effectSpecifiers?.asyncSpecifier
let throwsClause = self.signature.effectSpecifiers?.throwsClause

return MethodModel(name: "init",
typeName: "",
Expand All @@ -473,8 +484,14 @@ extension InitializerDeclSyntax {
genericTypeParams: genericTypeParams,
genericWhereClause: genericWhereClause,
params: params,
throwsOrRethrows: self.signature.effectSpecifiers?.throwsClause?.throwsSpecifier.text,
asyncOrReasync: self.signature.effectSpecifiers?.asyncSpecifier?.text,
throwsOrRethrows: throwsClause != nil ?
FunctionThrowsSuffix(
isRethrows: throwsClause!.throwsSpecifier.text == String.rethrows,
type: throwsClause!.type?.description
) : nil,
asyncOrReasync: asyncSpecifier != nil ? FunctionAsyncSuffix(
isReasync: asyncSpecifier!.text == String.rethrows
) : nil,
isStatic: false,
offset: self.offset,
length: self.length,
Expand Down
6 changes: 3 additions & 3 deletions Sources/MockoloFramework/Templates/ClosureTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ extension ClosureModel {
genericTypeNames: [String],
paramVals: [String]?,
paramTypes: [SwiftType]?,
suffix: String,
suffix: FunctionSuffixClause?,
returnDefaultType: SwiftType) -> String {

var handlerParamValsStr = ""
Expand All @@ -46,8 +46,8 @@ extension ClosureModel {
let handlerReturnDefault = renderReturnDefaultStatement(name: name, type: returnDefaultType)

let prefix = [
suffix.hasThrowsOrRethrows ? String.try + " " : nil,
suffix.hasAsync ? String.await + " " : nil,
suffix?.throwsSuffix != nil ? String.try + " " : nil,
suffix?.asyncSuffix != nil ? String.await + " " : nil,
].compactMap { $0 }.joined()

let returnStr = returnDefaultType.typeName.isEmpty ? "" : "return "
Expand Down
40 changes: 40 additions & 0 deletions Sources/MockoloFramework/Templates/FunctionSuffixTemplate.swift
fummicc1 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// 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.
//

extension FunctionSuffixClause {
func applyFunctionSuffixTemplate(
forClosureTemplate: Bool
) -> String {
var ret: String = ""
if let asyncSuffix {
ret += asyncSuffix.isReasync ? String.reasync : String.async
}
if let throwsSuffix {
if asyncSuffix != nil {
ret += " "
}
if !forClosureTemplate, throwsSuffix.isRethrows {
ret += String.rethrows
} else {
ret += String.throws
if let throwType = throwsSuffix.type {
ret += "(\(throwType))"
}
}
}
return ret
}
}
6 changes: 3 additions & 3 deletions Sources/MockoloFramework/Templates/MethodTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ extension MethodModel {
params: [ParamModel],
returnType: SwiftType,
accessLevel: String,
suffix: String,
suffix: FunctionSuffixClause?,
argsHistory: ArgumentsHistoryModel?,
handler: ClosureModel?) -> String {
var template = ""
Expand Down Expand Up @@ -59,14 +59,14 @@ extension MethodModel {
let handlerVarType = handler.type.typeName // ?? "Any"
let handlerReturn = handler.render(with: identifier, encloser: "") ?? ""

let suffixStr = suffix.isEmpty ? "" : "\(suffix) "
let suffixStr = suffix == nil ? "" : "\(suffix!.applyFunctionSuffixTemplate(forClosureTemplate: false)) "
let returnStr = returnTypeName.isEmpty ? "" : "-> \(returnTypeName)"
let staticStr = isStatic ? String.static + " " : ""
let keyword = isSubscript ? "" : "func "
var body = ""

if useTemplateFunc {
let callMockFunc = !suffix.hasThrowsOrRethrows && (handler.type.cast?.isEmpty ?? false)
let callMockFunc = suffix?.throwsSuffix == nil && (handler.type.cast?.isEmpty ?? false)
if callMockFunc {
let handlerParamValsStr = params.map { (arg) -> String in
if arg.type.typeName.hasPrefix(String.autoclosure) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/MockoloFramework/Templates/NominalTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ extension NominalModel {
let genericTypeDeclsStr = m.genericTypeParams.compactMap {$0.render(with: "", encloser: "")}.joined(separator: ", ")
let genericTypesStr = genericTypeDeclsStr.isEmpty ? "" : "<\(genericTypeDeclsStr)>"
let paramDeclsStr = m.params.compactMap{$0.render(with: "", encloser: "")}.joined(separator: ", ")
let suffixStr = m.suffix.isEmpty ? "" : "\(m.suffix) "
let suffixStr = m.suffix == nil ? "" : "\(m.suffix!.applyFunctionSuffixTemplate(forClosureTemplate: false)) "

if override {
let paramsList = m.params.map { param in
Expand Down
14 changes: 1 addition & 13 deletions Sources/MockoloFramework/Utils/StringExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extension String {
static let `throws` = "throws"
static let `rethrows` = "rethrows"
static let async = "async"
static let reasync = "reasync"
static let await = "await"
static let `inout` = "inout"
static let hasBlankInit = "_hasBlankInit"
Expand Down Expand Up @@ -110,19 +111,6 @@ extension String {
///
"""


var hasThrowsOrRethrows: Bool {
return components(separatedBy: .whitespaces).contains { component in
return component == .throws || component == .rethrows
}
}

var hasAsync: Bool {
return components(separatedBy: .whitespaces).contains { component in
return component == .async
}
}

var safeName: String {
var text = self
if let keyword = text.withSyntaxText(Keyword.init),
Expand Down
8 changes: 2 additions & 6 deletions Sources/MockoloFramework/Utils/TypeParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -511,8 +511,7 @@ public final class SwiftType {
return mutableArg
}


static func toClosureType(with params: [SwiftType], typeParams: [String], suffix: String, returnType: SwiftType, encloser: String) -> SwiftType {
static func toClosureType(with params: [SwiftType], typeParams: [String], suffix: FunctionSuffixClause?, returnType: SwiftType, encloser: String) -> SwiftType {


let displayableParamTypes = params.map { (subtype: SwiftType) -> String in
Expand Down Expand Up @@ -559,10 +558,7 @@ public final class SwiftType {
displayableReturnType = "(\(displayableReturnType))"
}

let suffixStr = [
suffix.hasAsync ? String.async + " " : nil,
suffix.hasThrowsOrRethrows ? String.throws + " " : nil,
].compactMap { $0 }.joined()
let suffixStr = suffix != nil ? "\(suffix!.applyFunctionSuffixTemplate(forClosureTemplate: true)) " : ""

Copy link
Collaborator

@sidepelican sidepelican Oct 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It want to avoid relying on internal implementations.

            let suffixStr = [
                isAsync ? String.async : nil,
                throwing.applyThrowingTemplate(),
            ].compactMap { $0 }.joined(separator: " ") + " "

(This snippet exists in the other 2 places. Maybe it's a time to add utility, not must)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds nice! I fixed it in these 2 commits.

let typeStr = "((\(displayableParamStr)) \(suffixStr)-> \(displayableReturnType))?"
return SwiftType(typeStr, cast: returnTypeCast)
Expand Down
Loading