Skip to content

Commit 9b98573

Browse files
committed
Add SwiftRefactor Library
SwiftRefactor provides a central place for tools that transform Swift source code to register their implementations. A syntactic refactoring provides a simple, strongly-typed, safe way to express the transformation process.
1 parent ce11d7a commit 9b98573

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

Package.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ let package = Package(
4141
.library(name: "SwiftSyntaxParser", type: .static, targets: ["SwiftSyntaxParser"]),
4242
.library(name: "SwiftSyntaxBuilder", type: .static, targets: ["SwiftSyntaxBuilder"]),
4343
.library(name: "_SwiftSyntaxMacros", type: .static, targets: ["_SwiftSyntaxMacros"]),
44+
.library(name: "SwiftRefactor", type: .static, targets: ["SwiftRefactor"]),
4445
],
4546
targets: [
4647
.target(
@@ -147,6 +148,11 @@ let package = Package(
147148
exclude: [
148149
"CMakeLists.txt",
149150
]),
151+
.target(
152+
name: "SwiftRefactor",
153+
dependencies: [
154+
"SwiftSyntax", "SwiftParser",
155+
]),
150156
.executableTarget(
151157
name: "lit-test-helper",
152158
dependencies: ["IDEUtils", "SwiftSyntax", "SwiftSyntaxParser"]
@@ -199,6 +205,11 @@ let package = Package(
199205
dependencies: ["SwiftOperators", "_SwiftSyntaxTestSupport",
200206
"SwiftParser"]
201207
),
208+
.testTarget(
209+
name: "SwiftRefactorTest",
210+
dependencies: [
211+
"SwiftRefactor", "SwiftSyntaxBuilder", "_SwiftSyntaxTestSupport",
212+
]),
202213
]
203214
)
204215

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import SwiftSyntax
2+
3+
/// A type that transforms syntax to provide a (context-sensitive)
4+
/// refactoring.
5+
///
6+
/// A type conforming to the `RefactoringProvider` protocol defines the
7+
/// a refactoring action against a family of Swift syntax trees.
8+
///
9+
/// Refactoring
10+
/// ===========
11+
///
12+
/// Refactoring is the act of transforming source code to be more effective.
13+
/// A refactoring does not affect the semantics of code it is transforming.
14+
/// Rather, it makes that code easier to read and reason about.
15+
///
16+
/// Code Transformation
17+
/// ===================
18+
///
19+
/// Refactoring is expressed as structural transformations of Swift
20+
/// syntax trees. The SwiftSyntax API provides a natural, easy-to-use,
21+
/// and compositional set of updates to the syntax tree. For example, a
22+
/// refactoring action that wishes to exchange the leading trivia of a node
23+
/// would call `withLeadingTrivia(_:)` against its input syntax and return
24+
/// the resulting syntax node. For compound syntax nodes, entire sub-trees
25+
/// can be added, exchanged, or removed by calling the corresponding `with`
26+
/// API.
27+
///
28+
/// - Note: The syntax trees returned by SwiftSyntax are immutable: any
29+
/// transformation made against the tree results in a distinct tree.
30+
///
31+
/// Handling Malformed Syntax
32+
/// =========================
33+
///
34+
/// A refactoring provider cannot assume that the syntax it is given is
35+
/// neessarily well-formed. As the SwiftSyntax library is capable of recovering
36+
/// from a variety of erroneous inputs, a refactoring provider has to be
37+
/// prepared to fail gracefully as well. Many refactoring providers follow a
38+
/// common validation pattern that "preflights" the refactoring by testing the
39+
/// structure of the provided syntax nodes. If the tests fail, the refactoring
40+
/// provider exits early by returning `nil`. It is recommended that refactoring
41+
/// actions fail as quickly as possible to give any associated tooling
42+
/// space to recover as well.
43+
public protocol RefactoringProvider {
44+
/// The type of syntax this refactoring action accepts.
45+
associatedtype Input: SyntaxProtocol = SourceFileSyntax
46+
/// The type of syntax this refactorign action returns.
47+
associatedtype Output: SyntaxProtocol = SourceFileSyntax
48+
/// Contextual information used by the refactoring action.
49+
associatedtype Context = Void
50+
51+
/// Perform the refactoring action on the provided syntax node.
52+
///
53+
/// - Parameters:
54+
/// - syntax: The syntax to transform.
55+
/// - context: Contextual information used by the refactoring action.
56+
/// - Returns: The result of applying the refactoring action, or `nil` if the
57+
/// action could not be performed.
58+
static func refactor(syntax: Self.Input, in context: Self.Context) -> Self.Output?
59+
}
60+
61+
extension RefactoringProvider where Context == Void {
62+
/// Perform the refactoring action on the provided syntax node.
63+
///
64+
/// This method provides a convenient way to invoke a refactoring action that
65+
/// requires no context.
66+
///
67+
/// - Parameters:
68+
/// - syntax: The syntax to transform.
69+
/// - Returns: The result of applying the refactoring action, or `nil` if the
70+
/// action could not be performed.
71+
public static func refactor(syntax: Self.Input) -> Self.Output? {
72+
return self.refactor(syntax: syntax, in: ())
73+
}
74+
}

0 commit comments

Comments
 (0)