Skip to content

Commit f29f3ce

Browse files
committed
[Macro] Add plugin test
1 parent 3f670dc commit f29f3ce

File tree

9 files changed

+123
-8
lines changed

9 files changed

+123
-8
lines changed

Examples/Package.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ let package = Package(
1010
products: [
1111
.executable(name: "AddOneToIntegerLiterals", targets: ["AddOneToIntegerLiterals"]),
1212
.executable(name: "CodeGenerationUsingSwiftSyntaxBuilder", targets: ["CodeGenerationUsingSwiftSyntaxBuilder"]),
13+
.executable(name: "ExamplePlugin", targets: ["ExamplePlugin"]),
1314
],
1415
dependencies: [
1516
.package(path: "../")
@@ -20,17 +21,21 @@ let package = Package(
2021
dependencies: [
2122
.product(name: "SwiftParser", package: "swift-syntax"),
2223
.product(name: "SwiftSyntax", package: "swift-syntax"),
23-
],
24-
path: ".",
25-
exclude: ["README.md", "CodeGenerationUsingSwiftSyntaxBuilder.swift"]
24+
]
2625
),
2726
.executableTarget(
2827
name: "CodeGenerationUsingSwiftSyntaxBuilder",
2928
dependencies: [
3029
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax")
31-
],
32-
path: ".",
33-
exclude: ["README.md", "AddOneToIntegerLiterals.swift"]
30+
]
3431
),
32+
.executableTarget(
33+
name: "ExamplePlugin",
34+
dependencies: [
35+
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
36+
.product(name: "SwiftSyntax", package: "swift-syntax"),
37+
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
38+
.product(name: "SwiftDiagnostics", package: "swift-syntax"),
39+
])
3540
]
3641
)

Examples/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
Each example can be executed by navigating into this folder and running `swift run <example> <arguments>`. There is the following set of examples available:
44

5-
- [AddOneToIntegerLiterals](AddOneToIntegerLiterals.swift): Command line tool to add 1 to every integer literal in a source file
6-
- [CodeGenerationUsingSwiftSyntaxBuilder](CodeGenerationUsingSwiftSyntaxBuilder.swift): Code-generate a simple source file using SwiftSyntaxBuilder
5+
- [AddOneToIntegerLiterals](Sources/AddOneToIntegerLiterals/AddOneToIntegerLiterals.swift): Command line tool to add 1 to every integer literal in a source file
6+
- [CodeGenerationUsingSwiftSyntaxBuilder](Sources/CodeGenerationUsingSwiftSyntaxBuilder/CodeGenerationUsingSwiftSyntaxBuilder.swift): Code-generate a simple source file using SwiftSyntaxBuilder
7+
- [ExamplePlugin](Sources/ExamplePlugn): Compiler plugin executable using [`SwiftCompilerPlugin`](../Sources/SwiftCompilerPlugin)
78

89
## Some Example Usages
910

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import SwiftCompilerPlugin
2+
import SwiftSyntaxMacros
3+
4+
@main
5+
struct ThePlugin: CompilerPlugin {
6+
var providingMacros: [Macro.Type] = [
7+
EchoExpressionMacro.self,
8+
MetadataMacro.self
9+
]
10+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import SwiftSyntax
2+
import SwiftSyntaxBuilder
3+
import SwiftSyntaxMacros
4+
5+
/// Returns the first argument prepending a comment '/* echo */'.
6+
struct EchoExpressionMacro: ExpressionMacro {
7+
static func expansion<
8+
Node: FreestandingMacroExpansionSyntax,
9+
Context: MacroExpansionContext
10+
>(
11+
of node: Node,
12+
in context: Context
13+
) throws -> ExprSyntax {
14+
let expr: ExprSyntax = node.argumentList.first!.expression
15+
return expr.with(\.leadingTrivia, [.blockComment("/* echo */")])
16+
}
17+
}
18+
19+
/// Add a static property `__metadata__`.
20+
struct MetadataMacro: MemberMacro {
21+
static func expansion<
22+
Declaration: DeclGroupSyntax,
23+
Context: MacroExpansionContext
24+
>(
25+
of node: SwiftSyntax.AttributeSyntax,
26+
providingMembersOf declaration: Declaration,
27+
in context: Context
28+
) throws -> [DeclSyntax] {
29+
guard let cls = declaration.as(ClassDeclSyntax.self) else {
30+
return []
31+
}
32+
let className = cls.identifier.trimmedDescription
33+
return [
34+
"""
35+
static var __metadata__: [String: String] { ["name": "\(raw: className)"] }
36+
"""
37+
]
38+
}
39+
}

build-script.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,12 @@ def run_lit_tests(toolchain: str, build_dir: Optional[str], release: bool,
564564
["--param", "INCR_TRANSFER_ROUND_TRIP.PY=" + INCR_TRANSFER_ROUNDTRIP_EXEC]
565565
)
566566

567+
build_subdir = 'release' if release else 'debug'
568+
package_build_dir = build_dir + '/' + build_subdir
569+
570+
lit_call.extend(["--param", "BUILD_DIR=" + package_build_dir])
571+
lit_call.extend(["--param", "TOOLCHAIN=" + toolchain])
572+
567573
# Print all failures
568574
lit_call.extend(["--verbose"])
569575
# Don't show all commands if verbose is not enabled
@@ -689,6 +695,7 @@ def test_command(args: argparse.Namespace) -> None:
689695
)
690696

691697
builder.buildProduct("lit-test-helper")
698+
builder.buildExample("ExamplePlugin")
692699

693700
run_tests(
694701
toolchain=args.toolchain,

lit_tests/compiler_plugin_basic.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// REQUIRES: platform=Darwin
2+
//
3+
// RUN: %empty-directory(%t)
4+
//
5+
// RUN: %swift-frontend -typecheck -swift-version 5 \
6+
// RUN: -enable-experimental-feature Macros \
7+
// RUN: -dump-macro-expansions \
8+
// RUN: -load-plugin-executable %build_dir/ExamplePlugin#ExamplePlugin \
9+
// RUN -module-name MyApp \
10+
// RUN: %s > %t/expansions-dump.txt 2>&1
11+
//
12+
// RUN: %FileCheck %s < %t/expansions-dump.txt
13+
14+
@freestanding(expression)
15+
macro echo<T>(_: T) -> T = #externalMacro(module: "ExamplePlugin", type: "EchoExpressionMacro")
16+
17+
@attached(member)
18+
macro Metadata() = #externalMacro(module: "ExamplePlugin", type: "MetadataMacro")
19+
20+
@Metadata
21+
class MyClass {
22+
var value: Int = #echo(12)
23+
}
24+
25+
// CHECK-LABEL: @__swiftmacro_21compiler_plugin_basic7MyClassC8MetadatafMm_.swift
26+
// CHECK-NEXT: ------------------------------
27+
// CHECK-NEXT: static var __metadata__: [String: String] { ["name": "MyClass"] }
28+
// CHECK-NEXT: ------------------------------
29+
30+
// CHECK-LABEL: @__swiftmacro_21compiler_plugin_basic7MyClassC5valueSivpfi4echofMf_.swift as Int
31+
// CHECK-NEXT: ------------------------------
32+
// CHECK-NEXT: /* echo */12
33+
// CHECK-NEXT: ------------------------------

lit_tests/lit.cfg

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# -----------------------------------------------------------------------------
1212

1313
import lit
14+
import platform
1415
import tempfile
1516

1617

@@ -25,6 +26,11 @@ def inferSwiftBinaryImpl(binaryName, envVarName):
2526
if execPath:
2627
return execPath
2728

29+
# Find in the toolchain.
30+
execPath = lit_config.params.get('TOOLCHAIN') + '/bin/' + binaryName
31+
if os.path.exists(execPath):
32+
return execPath
33+
2834
# Lastly, look in the path.
2935
return lit.util.which(binaryName, config.environment["PATH"])
3036

@@ -53,10 +59,21 @@ config.suffixes = [".swift"]
5359
config.test_format = lit.formats.ShTest(execute_external=True)
5460
config.test_exec_root = tempfile.gettempdir()
5561

62+
config.build_dir = lit_config.params.get("BUILD_DIR")
5663
config.filecheck = inferSwiftBinary("FileCheck")
5764
config.incr_transfer_round_trip = inferSwiftBinary("incr_transfer_round_trip.py")
5865
config.lit_test_helper = inferSwiftBinary("lit-test-helper")
66+
config.swift = inferSwiftBinary("swift")
67+
config.swiftc = inferSwiftBinary("swiftc")
68+
config.swift_frontend = inferSwiftBinary("swift-frontend")
69+
70+
# Use features like this in lit:
71+
# // REQUIRES: platform=<platform>
72+
# where <platform> is Linux or Darwin
73+
# Add a platform feature.
74+
config.available_features.add("platform="+platform.system())
5975

76+
config.substitutions.append(("%build_dir", config.build_dir))
6077
config.substitutions.append(
6178
("%empty-directory\(([^)]+)\)", 'rm -rf "\\1" && mkdir -p "\\1"')
6279
)
@@ -69,3 +86,6 @@ config.substitutions.append(
6986
)
7087
)
7188
config.substitutions.append(("%lit-test-helper", config.lit_test_helper))
89+
config.substitutions.append(("%swiftc", config.swiftc))
90+
config.substitutions.append(("%swift", config.swift))
91+
config.substitutions.append(("%swift-frontend", config.swift_frontend))

0 commit comments

Comments
 (0)