Skip to content

Update SourseKit version to release, fix errors, fix tests and documentation #3

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ let package = Package(
),
],
dependencies: [
// Depend on the latest Swift 5.9 prerelease of SwiftSyntax
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0-swift-5.9-DEVELOPMENT-SNAPSHOT-2023-04-25-b")
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0")
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
Expand Down
2 changes: 2 additions & 0 deletions Sources/ExtractCaseValue/ExtractCaseValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import ExtractCaseValueMacros
/// case relative(String)
/// case absolute(String)
/// case root
///
/// var path: String {
/// switch self {
/// case let .relative(__macro_local_4pathfMu_):
Expand Down Expand Up @@ -53,6 +54,7 @@ public macro ExtractCaseValue<T>(name: String, kind: CaseExtractionKind = .defau
/// case relative(String)
/// case absolute(String)
/// case root
///
/// var path: String {
/// switch self {
/// case let .relative(__macro_local_4pathfMu_):
Expand Down
6 changes: 6 additions & 0 deletions Sources/ExtractCaseValueMacros/Diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,9 @@ struct InsertDefaultValueItMessage: FixItMessage {
MessageID(domain: "Swift", id: "ExtractCaseValue.\(self)")
}
}

extension MacroExpansionContext {
func diagnose(_ diagnostic: ExtractCaseValueMacroDiagnostic, at node: some SyntaxProtocol, fixIts: [FixIt] = []) {
diagnose(diagnostic.diagnose(at: node, fixIts: fixIts))
}
}
58 changes: 35 additions & 23 deletions Sources/ExtractCaseValueMacros/ExtractCaseValueMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@ extension ExtractCaseValueMacro: MemberMacro {
) throws -> [DeclSyntax] {
// Only apply to enums
guard let enumDecl = declaration.as(EnumDeclSyntax.self) else {
context.diagnose(ExtractCaseValueMacroDiagnostic.requiresEnum.diagnose(at: declaration))
context.diagnose(.requiresEnum, at: declaration)
return []
}

guard
let arguments = attribute.argument,
let arguments = attribute.arguments,
case let .argumentList(arguments) = arguments
else {
context.diagnose(ExtractCaseValueMacroDiagnostic.requiresArgs.diagnose(at: attribute))
context.diagnose(.requiresArgs, at: attribute)
return []
}

// get `name` argument
guard let propertyNameArg = arguments.first(labeled: caseParamExtractionPropertyNameArgumentLabel) else {
context.diagnose(ExtractCaseValueMacroDiagnostic.requiresPropertyNameArg.diagnose(at: attribute))
context.diagnose(.requiresPropertyNameArg, at: attribute)
return []
}

guard let propertyNameString = propertyNameArg.expression.stringLiteralSegment else {
context.diagnose(ExtractCaseValueMacroDiagnostic.requiresPropertyNameStringLiteral.diagnose(at: propertyNameArg.expression))
context.diagnose(.requiresPropertyNameStringLiteral, at: propertyNameArg.expression)
return []
}

Expand All @@ -59,12 +59,12 @@ extension ExtractCaseValueMacro: MemberMacro {
// get expected type
guard
let returnType = attribute
.attributeName.as(SimpleTypeIdentifierSyntax.self)?
.attributeName.as(IdentifierTypeSyntax.self)?
.genericArgumentClause?
.arguments.first?
.argumentType
.argument
else {
context.diagnose(ExtractCaseValueMacroDiagnostic.requiresGenericType.diagnose(at: attribute))
context.diagnose(.requiresGenericType, at: attribute)
return []
}

Expand All @@ -83,10 +83,11 @@ extension ExtractCaseValueMacro: MemberMacro {

// create fix-it to add a default value if necessary
guard
let tupleList = attribute.argument?.as(TupleExprElementListSyntax.self)
let tupleList = attribute.arguments?.as(LabeledExprListSyntax.self)
else { return [] }
let expr: ExprSyntax = ", \(propertyNameString): <#Type#>"
let newTupleList = tupleList.inserting(TupleExprElementSyntax(expression: expr), at: tupleList.count)
var newTupleList = tupleList
newTupleList.append(LabeledExprSyntax(expression: expr))

let insertDefaultFixIt = FixIt(
message: InsertDefaultValueItMessage(),
Expand All @@ -98,21 +99,21 @@ extension ExtractCaseValueMacro: MemberMacro {
let elements = caseDecls.flatMap(\.elements)

// infer access modifier from enum
let access = enumDecl.modifiers?.first(where: \.isNeededAccessLevelModifier)
let access = enumDecl.modifiers.first(where: \.isNeededAccessLevelModifier)

var switchCaseSyntaxes: [SwitchCaseSyntax] = []

for element in elements {
let caseSyntax = element.as(EnumCaseElementSyntax.self)!

guard let paramList = caseSyntax.associatedValue?.parameterList else {
guard let paramList = caseSyntax.parameterClause?.parameters else {
if let defaultValue {
switchCaseSyntaxes.append(
"case .\(element.identifier): return \(defaultValue)"
"case .\(element.name): return \(defaultValue)"
)
continue
} else {
context.diagnose(ExtractCaseValueMacroDiagnostic.noAssociatedValues(case: element.identifier.text).diagnose(at: element, fixIts: [insertDefaultFixIt]))
context.diagnose(.noAssociatedValues(case: element.name.text), at: element, fixIts: [insertDefaultFixIt])
return []
}
}
Expand All @@ -127,18 +128,18 @@ extension ExtractCaseValueMacro: MemberMacro {
else {
if let defaultValue {
switchCaseSyntaxes.append(
"case .\(element.identifier): return \(defaultValue)"
"case .\(element.name): return \(defaultValue)"
)
didUseDefaultValue = true
break
} else {
context.diagnose(ExtractCaseValueMacroDiagnostic.noValue(case: element.identifier.text, index: index).diagnose(at: element, fixIts: [insertDefaultFixIt]))
context.diagnose(.noValue(case: element.name.text, index: index), at: element, fixIts: [insertDefaultFixIt])
return []
}
}

guard associatedValue.element.type.matchesReturnType(returnType) else {
context.diagnose(ExtractCaseValueMacroDiagnostic.typeMismatch(case: element.identifier.text, index: index).diagnose(at: associatedValue.element))
context.diagnose(.typeMismatch(case: element.name.text, index: index), at: associatedValue.element)
return []
}

Expand All @@ -148,18 +149,25 @@ extension ExtractCaseValueMacro: MemberMacro {
guard let associatedValue = paramList.first(labeled: name), let index = paramList.firstIndex(of: name) else {
if let defaultValue {
switchCaseSyntaxes.append(
"case .\(element.identifier): return \(defaultValue)"
"case .\(element.name): return \(defaultValue)"
)
didUseDefaultValue = true
break
} else {
context.diagnose(ExtractCaseValueMacroDiagnostic.noAssociatedValueForName(name: name, case: element.identifier.text).diagnose(at: element, fixIts: [insertDefaultFixIt]))
context.diagnose(
.noAssociatedValueForName(name: name, case: element.name.text),
at: element,
fixIts: [insertDefaultFixIt]
)
return []
}
}

guard associatedValue.type.matchesReturnType(returnType) else {
context.diagnose(ExtractCaseValueMacroDiagnostic.typeMismatchNamed(name: name, case: element.identifier.text).diagnose(at: associatedValue))
context.diagnose(
.typeMismatchNamed(name: name, case: element.name.text),
at: associatedValue
)
return []
}

Expand All @@ -170,12 +178,16 @@ extension ExtractCaseValueMacro: MemberMacro {
else {
if let defaultValue {
switchCaseSyntaxes.append(
"case .\(element.identifier): return \(defaultValue)"
"case .\(element.name): return \(defaultValue)"
)
didUseDefaultValue = true
break
} else {
context.diagnose(ExtractCaseValueMacroDiagnostic.noMatchingType(type: "\(returnType)", case: element.identifier.text).diagnose(at: element, fixIts: [insertDefaultFixIt]))
context.diagnose(
.noMatchingType(type: "\(returnType)", case: element.name.text),
at: element,
fixIts: [insertDefaultFixIt]
)
return []
}
}
Expand All @@ -192,7 +204,7 @@ extension ExtractCaseValueMacro: MemberMacro {
.joined(separator: ", ")

switchCaseSyntaxes.append(
"case let .\(element.identifier)(\(raw: variablesAndUnderscores)): return \(uniqueVariableName)"
"case let .\(element.name)(\(raw: variablesAndUnderscores)): return \(uniqueVariableName)"
)
}

Expand Down
26 changes: 16 additions & 10 deletions Tests/ExtractCaseValueTests/ExtractCaseValueTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ final class ExtractCaseValueTests: XCTestCase {
case relative(String)
case absolute(String)
case root

var path: String {
switch self {
case let .relative(__macro_local_4pathfMu_):
Expand Down Expand Up @@ -57,6 +58,7 @@ final class ExtractCaseValueTests: XCTestCase {
case relative(String)
case absolute(String)
case root

public var path: String {
switch self {
case let .relative(__macro_local_4pathfMu_):
Expand Down Expand Up @@ -88,6 +90,7 @@ final class ExtractCaseValueTests: XCTestCase {
enum Coordinate {
case twoDee(x: Double, y: Double)
case threeDee(x: Double, y: Double, z: Double)

var x: Double {
switch self {
case let .twoDee(__macro_local_1xfMu_, _):
Expand Down Expand Up @@ -119,6 +122,7 @@ final class ExtractCaseValueTests: XCTestCase {
case relative(String)
case absolute(String)
case root

var path: String {
switch self {
case let .relative(__macro_local_4pathfMu_):
Expand Down Expand Up @@ -150,6 +154,7 @@ final class ExtractCaseValueTests: XCTestCase {
enum Coordinate {
case twoDee(x: Double, y: Double)
case threeDee(x: Double, y: Double, z: Double)

var y: Double {
switch self {
case let .twoDee(_, __macro_local_1yfMu_):
Expand Down Expand Up @@ -179,6 +184,7 @@ final class ExtractCaseValueTests: XCTestCase {
enum Coordinate {
case twoDee(x: Double, y: Double)
case threeDee(x: Double, y: Double, z: Double)

var z: Double? {
switch self {
case .twoDee:
Expand Down Expand Up @@ -210,6 +216,7 @@ final class ExtractCaseValueTests: XCTestCase {
enum Coordinate {
case twoDee(x: Double, y: Double)
case threeDee(x: Double, y: Double, z: Double)

var x: Double {
switch self {
case let .twoDee(__macro_local_1xfMu_, _):
Expand All @@ -218,6 +225,7 @@ final class ExtractCaseValueTests: XCTestCase {
return __macro_local_1xfMu0_
}
}

var y: Double {
switch self {
case let .twoDee(_, __macro_local_1yfMu_):
Expand All @@ -226,6 +234,7 @@ final class ExtractCaseValueTests: XCTestCase {
return __macro_local_1yfMu0_
}
}

var z: Double? {
switch self {
case .twoDee:
Expand Down Expand Up @@ -263,6 +272,7 @@ final class ExtractCaseValueTests: XCTestCase {
case array([_JSON])
case bool(Bool)
case null

var string: String? {
switch self {
case let .string(__macro_local_6stringfMu_):
Expand Down Expand Up @@ -294,8 +304,7 @@ final class ExtractCaseValueTests: XCTestCase {
""",
expandedSource: """

struct NotAnEnum {
}
struct NotAnEnum {}
""",
diagnostics: [
.init(message: "'ExtractCaseValue' macro can only be applied to an enum", line: 1, column: 1)
Expand All @@ -313,8 +322,7 @@ final class ExtractCaseValueTests: XCTestCase {
""",
expandedSource: """

enum AnEnum {
}
enum AnEnum {}
""",
diagnostics: [
.init(message: "'ExtractCaseValue' macro requires arguments", line: 1, column: 1)
Expand All @@ -332,8 +340,7 @@ final class ExtractCaseValueTests: XCTestCase {
""",
expandedSource: """

enum AnEnum {
}
enum AnEnum {}
""",
diagnostics: [
.init(message: "'ExtractCaseValue' macro requires `name` argument", line: 1, column: 1)
Expand All @@ -351,8 +358,7 @@ final class ExtractCaseValueTests: XCTestCase {
""",
expandedSource: """

enum AnEnum {
}
enum AnEnum {}
""",
diagnostics: [
.init(message: "'ExtractCaseValue' macro argument `name` must be a string literal", line: 1, column: 33)
Expand All @@ -370,8 +376,7 @@ final class ExtractCaseValueTests: XCTestCase {
""",
expandedSource: """

enum AnEnum {
}
enum AnEnum {}
""",
diagnostics: [
.init(message: "'ExtractCaseValue' macro requires a generic type for the computed property", line: 1, column: 1)
Expand Down Expand Up @@ -569,6 +574,7 @@ final class ExtractCaseValueTests: XCTestCase {
enum Coordinate {
case twoDee(x: Double, y: Double)
case threeDee(x: Double, y: Double, z: Double)

var a: Double? {
switch self {
case .twoDee:
Expand Down