Skip to content

Commit 68143a0

Browse files
committed
Fix protoc plugin
1 parent 10dd827 commit 68143a0

File tree

8 files changed

+81
-23
lines changed

8 files changed

+81
-23
lines changed

protobuf-plugin/build.gradle.kts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ sourceSets {
5151
tasks.jar {
5252
manifest {
5353
attributes["Main-Class"] = "kotlinx.rpc.protobuf.MainKt"
54-
5554
}
55+
5656
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
57+
archiveClassifier = "all"
5758

5859
// Protoc plugins are all fat jars basically (the ones built on jvm)
5960
// be really careful of what you put in the classpath here
@@ -73,7 +74,7 @@ protobuf {
7374

7475
plugins {
7576
create("kotlinx-rpc") {
76-
path = "$buildDirPath/libs/protobuf-plugin-$version.jar"
77+
path = "$buildDirPath/libs/protobuf-plugin-$version-all.jar"
7778
}
7879

7980
create("grpc") {

protobuf-plugin/src/main/kotlin/kotlinx/rpc/protobuf/CodeGenerator.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ class FileGenerator(
255255
codeGenerationParameters: CodeGenerationParameters,
256256
var filename: String? = null,
257257
var packageName: String? = null,
258+
var fileOptIns: List<String> = emptyList(),
258259
logger: Logger = NOPLogger.NOP_LOGGER,
259260
) : CodeGenerator(codeGenerationParameters, "", logger = logger) {
260261
private val imports = mutableListOf<String>()
@@ -272,7 +273,13 @@ class FileGenerator(
272273
override fun build(): String {
273274
val sortedImports = imports.toSortedSet()
274275
val prefix = buildString {
275-
if (packageName != null) {
276+
if (fileOptIns.isNotEmpty()) {
277+
appendLine("@file:OptIn(${fileOptIns.joinToString(", ")})")
278+
newLine()
279+
}
280+
281+
var packageName = packageName
282+
if (packageName != null && packageName.isNotEmpty()) {
276283
appendLine("package $packageName")
277284
}
278285

@@ -297,4 +304,4 @@ fun file(
297304
packageName: String? = null,
298305
logger: Logger = NOPLogger.NOP_LOGGER,
299306
block: FileGenerator.() -> Unit,
300-
): FileGenerator = FileGenerator(codeGenerationParameters, name, packageName, logger).apply(block)
307+
): FileGenerator = FileGenerator(codeGenerationParameters, name, packageName, emptyList(), logger).apply(block)

protobuf-plugin/src/main/kotlin/kotlinx/rpc/protobuf/ModelToKotlinGenerator.kt

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class ModelToKotlinGenerator(
2121
return file(codeGenerationParameters, logger = logger) {
2222
filename = name.simpleName
2323
packageName = name.packageName
24+
fileOptIns = listOf("ExperimentalRpcApi::class", "InternalRpcApi::class")
2425

2526
dependencies.forEach { dependency ->
2627
importPackage(dependency.name.packageName)
@@ -31,6 +32,7 @@ class ModelToKotlinGenerator(
3132
additionalImports.forEach {
3233
import(it)
3334
}
35+
import("kotlinx.rpc.internal.utils.*")
3436
}
3537
}
3638

@@ -115,8 +117,7 @@ class ModelToKotlinGenerator(
115117
}
116118
}
117119

118-
val platformType = "${declaration.name.packageName}.${declaration.name.simpleName}OuterClass." +
119-
declaration.name.simpleName
120+
val platformType = "${declaration.outerClassName.simpleName}.${declaration.name.simpleName}"
120121

121122
function(
122123
name = "toPlatform",
@@ -244,11 +245,13 @@ class ModelToKotlinGenerator(
244245
clazz(service.name.simpleName, declarationType = DeclarationType.Interface) {
245246
service.methods.forEach { method ->
246247
// no streaming for now
248+
val inputType by method.inputType
249+
val outputType by method.outputType
247250
function(
248251
name = method.name.simpleName,
249252
modifiers = "suspend",
250-
args = "message: ${method.inputType.simpleName}",
251-
returnType = method.outputType.simpleName,
253+
args = "message: ${inputType.name.simpleName}",
254+
returnType = outputType.name.simpleName,
252255
)
253256
}
254257
}
@@ -292,11 +295,14 @@ class ModelToKotlinGenerator(
292295
service.methods.forEach { method ->
293296
val grpcName = method.name.simpleName.replaceFirstChar { it.lowercase() }
294297

298+
val inputType by method.inputType
299+
val outputType by method.outputType
300+
295301
function(
296302
name = grpcName,
297303
modifiers = "override suspend",
298-
args = "request: ${method.inputType.toPlatformMessageType()}",
299-
returnType = method.outputType.toPlatformMessageType(),
304+
args = "request: ${inputType.toPlatformMessageType()}",
305+
returnType = outputType.toPlatformMessageType(),
300306
) {
301307
code("return impl.${method.name.simpleName}(request.toKotlin()).toPlatform()")
302308
}
@@ -334,8 +340,9 @@ class ModelToKotlinGenerator(
334340
code("@Suppress(\"UNCHECKED_CAST\")")
335341
scope("return when (call.callableName)") {
336342
service.methods.forEach { method ->
343+
val inputType by method.inputType
337344
val grpcName = method.name.simpleName.replaceFirstChar { it.lowercase() }
338-
val result = "stub.$grpcName((message as ${method.inputType.simpleName}).toPlatform())"
345+
val result = "stub.$grpcName((message as ${inputType.name.simpleName}).toPlatform())"
339346
code("\"${method.name.simpleName}\" -> $result.toKotlin() as R")
340347
}
341348

@@ -355,7 +362,7 @@ class ModelToKotlinGenerator(
355362
}
356363
}
357364

358-
private fun FqName.toPlatformMessageType(): String {
359-
return "${simpleName}OuterClass.${simpleName.removePrefix("$packageName.")}"
365+
private fun MessageDeclaration.toPlatformMessageType(): String {
366+
return "${outerClassName.simpleName}.${name.simpleName.removePrefix(name.parentNameAsPrefix)}"
360367
}
361368
}

protobuf-plugin/src/main/kotlin/kotlinx/rpc/protobuf/ProtoToModelInterpreter.kt

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class ProtoToModelInterpreter(
1818
private val logger: Logger,
1919
) {
2020
private val fileDependencies = mutableMapOf<String, FileDeclaration>()
21+
private val messages = mutableMapOf<FqName, MessageDeclaration>()
2122

2223
fun interpretProtocRequest(message: CodeGeneratorRequest): Model {
2324
return Model(message.protoFileList.map { it.toModel() })
@@ -40,7 +41,7 @@ class ProtoToModelInterpreter(
4041
simpleName = kotlinFileName(name)
4142
),
4243
dependencies = dependencies,
43-
messageDeclarations = messageTypeList.map { it.toModel() },
44+
messageDeclarations = messageTypeList.map { it.toModel(fqOuterClass()) },
4445
enumDeclarations = enumTypeList.map { it.toModel() },
4546
serviceDeclarations = serviceList.map { it.toModel() },
4647
deprecated = options.deprecated,
@@ -50,6 +51,10 @@ class ProtoToModelInterpreter(
5051
}
5152
}
5253

54+
private fun DescriptorProtos.FileDescriptorProto.fqOuterClass(): FqName {
55+
return "${name.removeSuffix(".proto").fullProtoNameToKotlin(firstLetterUpper = true)}OuterClass".toFqName()
56+
}
57+
5358
private fun kotlinFileName(originalName: String): String {
5459
return "${originalName.removeSuffix(".proto").fullProtoNameToKotlin(firstLetterUpper = true)}.kt"
5560
}
@@ -59,7 +64,7 @@ class ProtoToModelInterpreter(
5964
return originalPackage
6065
}
6166

62-
private fun DescriptorProtos.DescriptorProto.toModel(): MessageDeclaration {
67+
private fun DescriptorProtos.DescriptorProto.toModel(outerClass: FqName): MessageDeclaration {
6368
val fields = fieldList.mapNotNull {
6469
val oneOfName = if (it.hasOneofIndex()) {
6570
oneofDeclList[it.oneofIndex].name
@@ -71,14 +76,22 @@ class ProtoToModelInterpreter(
7176
}
7277

7378
return MessageDeclaration(
79+
outerClassName = outerClass,
7480
name = name.fullProtoNameToKotlin(firstLetterUpper = true).toFqName(),
7581
actualFields = fields,
7682
oneOfDeclarations = oneofDeclList.mapIndexedNotNull { i, desc -> desc.toModel(i) },
7783
enumDeclarations = enumTypeList.map { it.toModel() },
78-
nestedDeclarations = nestedTypeList.map { it.toModel() },
84+
nestedDeclarations = nestedTypeList.map { it.toModel(outerClass) },
7985
deprecated = options.deprecated,
8086
doc = null,
81-
)
87+
).apply {
88+
val name = if (packageName.isEmpty()) {
89+
name
90+
} else {
91+
"$packageName.$name".toFqName()
92+
}
93+
messages[name] = this
94+
}
8295
}
8396

8497
private val oneOfFieldMembers = mutableMapOf<Int, MutableList<DescriptorProtos.FieldDescriptorProto>>()
@@ -250,10 +263,12 @@ class ProtoToModelInterpreter(
250263
name = name.fullProtoNameToKotlin(firstLetterUpper = false).toFqName(),
251264
inputType = inputType
252265
.substringAfter('.') // see typeName resolution
253-
.fullProtoNameToKotlin(firstLetterUpper = true).toFqName(), // no resolution for now
266+
.fullProtoNameToKotlin(firstLetterUpper = true).toFqName()
267+
.let { lazy { messages[it] ?: error("Unknown message type $it, available: ${messages.keys.joinToString(",")}") } },
254268
outputType = outputType
255269
.substringAfter('.') // see typeName resolution
256-
.fullProtoNameToKotlin(firstLetterUpper = true).toFqName(), // no resolution for now
270+
.fullProtoNameToKotlin(firstLetterUpper = true).toFqName()
271+
.let { lazy { messages[it] ?: error("Unknown message type $it, available: ${messages.keys.joinToString(",")}") } },
257272
clientStreaming = clientStreaming,
258273
serverStreaming = serverStreaming,
259274
)
@@ -271,7 +286,7 @@ class ProtoToModelInterpreter(
271286
}
272287
}
273288

274-
private val snakeRegExp = "_[a-z]".toRegex()
289+
private val snakeRegExp = "(_[a-z]|-[a-z])".toRegex()
275290

276291
private fun String.snakeToCamelCase(): String {
277292
return replace(snakeRegExp) { it.value.last().uppercase() }

protobuf-plugin/src/main/kotlin/kotlinx/rpc/protobuf/model/FqName.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,24 @@ interface FqName {
88
val packageName: String
99
val simpleName: String
1010
val parentName: FqName?
11+
12+
val parentNameAsPrefix: String get() = parentName?.let { "$it.".removePrefix(".") } ?: ""
1113
}
1214

1315
data class SimpleFqName(
1416
override val packageName: String,
1517
override val simpleName: String,
1618
override val parentName: FqName? = null,
17-
): FqName
19+
): FqName {
20+
override fun equals(other: Any?): Boolean {
21+
return other is FqName && simpleName == other.simpleName
22+
}
23+
24+
override fun hashCode(): Int {
25+
return simpleName.hashCode()
26+
}
27+
28+
override fun toString(): String {
29+
return simpleName
30+
}
31+
}

protobuf-plugin/src/main/kotlin/kotlinx/rpc/protobuf/model/MessageDeclaration.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package kotlinx.rpc.protobuf.model
66

77
data class MessageDeclaration(
8+
val outerClassName: FqName,
89
val name: FqName,
910
val actualFields: List<FieldDeclaration>, // excludes oneOf fields, but includes oneOf itself
1011
val oneOfDeclarations: List<OneOfDeclaration>,

protobuf-plugin/src/main/kotlin/kotlinx/rpc/protobuf/model/MethodDeclaration.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ data class MethodDeclaration(
88
val name: FqName,
99
val clientStreaming: Boolean,
1010
val serverStreaming: Boolean,
11-
val inputType: FqName,
12-
val outputType: FqName,
11+
val inputType: Lazy<MessageDeclaration>,
12+
val outputType: Lazy<MessageDeclaration>,
1313
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
syntax = "proto3";
2+
3+
message Image {
4+
bytes data = 1;
5+
}
6+
7+
message RecogniseResult {
8+
int32 category = 1;
9+
}
10+
11+
service ImageRecognizer {
12+
rpc recognize(Image) returns (RecogniseResult);
13+
}

0 commit comments

Comments
 (0)