Skip to content

Commit 9f73676

Browse files
committed
Rewrite and generalize ConstructorCallCodegen for multipurpose usage.
1 parent bee3702 commit 9f73676

37 files changed

+1638
-625
lines changed

mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.WtLoginExt
2323
import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.analysisTlv0x531
2424
import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.orEmpty
2525
import net.mamoe.mirai.internal.utils.crypto.TEA
26-
import net.mamoe.mirai.internal.utils.printStructurally
26+
import net.mamoe.mirai.internal.utils.printStructure
2727
import net.mamoe.mirai.internal.utils.structureToString
2828
import net.mamoe.mirai.utils.*
2929

@@ -163,7 +163,7 @@ internal class WtLogin {
163163
val tlvMap: TlvMap = this._readTLVMap()
164164

165165
if (SHOW_TLV_MAP_ON_LOGIN_SUCCESS) {
166-
tlvMap.smartToString().printStructurally("tlvMap outer")
166+
tlvMap.smartToString().printStructure("tlvMap outer")
167167
}
168168

169169
// tlvMap.printTLVMap()
@@ -266,7 +266,7 @@ internal class WtLogin {
266266
val tlvMap119 = this._readTLVMap()
267267

268268
if (SHOW_TLV_MAP_ON_LOGIN_SUCCESS) {
269-
tlvMap119.smartToString().printStructurally("TlvMap119")
269+
tlvMap119.smartToString().printStructure("TlvMap119")
270270
}
271271

272272
tlvMap119[0x106]?.let { client.analyzeTlv106(it) }
@@ -366,7 +366,7 @@ internal class WtLogin {
366366
} ?: emptyMap()
367367

368368
if (SHOW_TLV_MAP_ON_LOGIN_SUCCESS) {
369-
changeTokenTimeMap.structureToString().printStructurally("tokenChangeTime")
369+
changeTokenTimeMap.structureToString().printStructure("tokenChangeTime")
370370
}
371371

372372
val outPSKeyMap: PSKeyMap?

mirai-core/src/commonMain/kotlin/utils/contentToString.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ private val SoutvLogger: MiraiLogger by lazy {
4141
level = DeprecationLevel.ERROR
4242
)
4343
@DeprecatedSinceMirai(errorSince = "2.10")
44-
internal fun Any?.soutv(name: String = "unnamed") = this.printStructurally(name)
44+
internal fun Any?.soutv(name: String = "unnamed") = this.printStructure(name)
4545

46-
internal fun Any?.printStructurally(name: String = "unnamed") {
46+
internal fun Any?.printStructure(name: String = "unnamed") {
4747
return SoutvLogger.debug { "$name = ${this.structureToString()}" }
4848
}
4949

mirai-core/src/commonMain/kotlin/utils/io/serialization/utils.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.OidbSso
2424
import net.mamoe.mirai.internal.utils.io.JceStruct
2525
import net.mamoe.mirai.internal.utils.io.ProtoBuf
2626
import net.mamoe.mirai.internal.utils.io.serialization.tars.Tars
27-
import net.mamoe.mirai.internal.utils.printStructurally
27+
import net.mamoe.mirai.internal.utils.printStructure
2828
import net.mamoe.mirai.utils.read
2929
import net.mamoe.mirai.utils.readPacketExact
3030
import kotlin.contracts.InvocationKind
@@ -171,7 +171,7 @@ internal fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrate
171171
internal fun <T : ProtoBuf> ByteArray.loadOidb(deserializer: DeserializationStrategy<T>, log: Boolean = false): T {
172172
val oidb = loadAs(OidbSso.OIDBSSOPkg.serializer())
173173
if (log) {
174-
oidb.printStructurally("OIDB")
174+
oidb.printStructure("OIDB")
175175
}
176176
return oidb.bodybuffer.loadAs(deserializer)
177177
}

mirai-core/src/commonTest/kotlin/notice/test/RecordingNoticeProcessorTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ package net.mamoe.mirai.internal.notice.test
1212
import kotlinx.serialization.Serializable
1313
import kotlinx.serialization.decodeFromString
1414
import kotlinx.serialization.protobuf.ProtoNumber
15-
import net.mamoe.mirai.internal.notice.Desensitizer
15+
import net.mamoe.mirai.internal.testFramework.desensitizer.Desensitizer
1616
import net.mamoe.mirai.internal.test.AbstractTest
1717
import net.mamoe.mirai.internal.utils.io.ProtocolStruct
1818
import net.mamoe.yamlkt.Yaml

mirai-core/src/commonTest/kotlin/utils/codegen/ValueDescVisitor.kt mirai-core/src/commonTest/kotlin/testFramework/codegen/RemoveDefaultValuesVisitor.kt

+21-95
Original file line numberDiff line numberDiff line change
@@ -7,107 +7,33 @@
77
* https://github.com/mamoe/mirai/blob/dev/LICENSE
88
*/
99

10-
package net.mamoe.mirai.internal.utils.codegen
11-
12-
import net.mamoe.mirai.utils.cast
13-
import kotlin.reflect.KClass
10+
package net.mamoe.mirai.internal.testFramework.codegen
11+
12+
import net.mamoe.mirai.internal.testFramework.codegen.descriptors.ClassValueDesc
13+
import net.mamoe.mirai.internal.testFramework.codegen.descriptors.ValueDesc
14+
import net.mamoe.mirai.internal.testFramework.codegen.descriptors.accept
15+
import net.mamoe.mirai.internal.testFramework.codegen.visitor.ValueDescVisitorUnit
16+
import net.mamoe.mirai.internal.testFramework.codegen.visitors.AnalyzeDefaultValuesMappingVisitor
17+
import net.mamoe.mirai.internal.testFramework.codegen.visitors.DefaultValuesMapping
1418
import kotlin.reflect.KParameter
15-
import kotlin.reflect.KProperty
16-
import kotlin.reflect.KProperty1
17-
import kotlin.reflect.full.memberProperties
18-
import kotlin.reflect.full.primaryConstructor
19-
20-
interface ValueDescVisitor {
21-
fun visitValue(desc: ValueDesc) {}
22-
23-
fun visitPlain(desc: PlainValueDesc) {
24-
visitValue(desc)
25-
}
26-
27-
fun visitArray(desc: ArrayValueDesc) {
28-
visitValue(desc)
29-
for (element in desc.elements) {
30-
element.accept(this)
31-
}
32-
}
33-
34-
fun visitObjectArray(desc: ObjectArrayValueDesc) {
35-
visitArray(desc)
36-
}
3719

38-
fun visitCollection(desc: CollectionValueDesc) {
39-
visitArray(desc)
40-
}
4120

42-
fun visitMap(desc: MapValueDesc) {
43-
visitValue(desc)
44-
for ((key, value) in desc.elements.entries) {
45-
key.accept(this)
46-
value.accept(this)
47-
}
48-
}
49-
50-
fun visitPrimitiveArray(desc: PrimitiveArrayValueDesc) {
51-
visitArray(desc)
52-
}
53-
54-
fun <T : Any> visitClass(desc: ClassValueDesc<T>) {
55-
visitValue(desc)
56-
desc.properties.forEach { (_, u) ->
57-
u.accept(this)
58-
}
59-
}
60-
}
61-
62-
63-
class DefaultValuesMapping(
64-
val forClass: KClass<*>,
65-
val mapping: MutableMap<String, Any?> = mutableMapOf()
66-
) {
67-
operator fun get(property: KProperty<*>): Any? = mapping[property.name]
68-
}
69-
70-
class AnalyzeDefaultValuesMappingVisitor : ValueDescVisitor {
71-
val mappings: MutableList<DefaultValuesMapping> = mutableListOf()
72-
73-
override fun <T : Any> visitClass(desc: ClassValueDesc<T>) {
74-
super.visitClass(desc)
75-
76-
if (mappings.any { it.forClass == desc.type }) return
77-
78-
val defaultInstance =
79-
createInstanceWithMostDefaultValues(desc.type, desc.properties.mapValues { it.value.origin })
80-
81-
val optionalParameters = desc.type.primaryConstructor!!.parameters.filter { it.isOptional }
82-
83-
mappings.add(
84-
DefaultValuesMapping(
85-
desc.type,
86-
optionalParameters.associateTo(mutableMapOf()) { param ->
87-
val value = findCorrespondingProperty(desc, param).get(defaultInstance)
88-
param.name!! to value
89-
}
90-
)
91-
)
92-
}
93-
94-
95-
private fun <T : Any> findCorrespondingProperty(
96-
desc: ClassValueDesc<T>,
97-
param: KParameter
98-
) = desc.type.memberProperties.single { it.name == param.name }.cast<KProperty1<Any, Any>>()
99-
100-
private fun <T : Any> createInstanceWithMostDefaultValues(clazz: KClass<T>, arguments: Map<KParameter, Any?>): T {
101-
val primaryConstructor = clazz.primaryConstructor ?: error("Type $clazz does not have primary constructor.")
102-
return primaryConstructor.callBy(arguments.filter { !it.key.isOptional })
103-
}
21+
fun ValueDesc.removeDefaultValues(): ValueDesc {
22+
val def = AnalyzeDefaultValuesMappingVisitor()
23+
this.accept(def)
24+
this.accept(RemoveDefaultValuesVisitor(def.mappings))
25+
return this
10426
}
10527

10628
class RemoveDefaultValuesVisitor(
10729
private val mappings: MutableList<DefaultValuesMapping>,
108-
) : ValueDescVisitor {
109-
override fun <T : Any> visitClass(desc: ClassValueDesc<T>) {
110-
super.visitClass(desc)
30+
) : ValueDescVisitorUnit {
31+
override fun visitValue(desc: ValueDesc, data: Nothing?) {
32+
desc.acceptChildren(this, data)
33+
}
34+
35+
override fun <T : Any> visitClass(desc: ClassValueDesc<T>, data: Nothing?) {
36+
super.visitClass(desc, data)
11137
val mapping = mappings.find { it.forClass == desc.type }?.mapping ?: return
11238

11339
// remove properties who have the same values as their default values, this would significantly reduce code size.
@@ -175,4 +101,4 @@ class RemoveDefaultValuesVisitor(
175101
else -> false
176102
}
177103
}
178-
}
104+
}

mirai-core/src/commonTest/kotlin/utils/codegen/ConstructorCallCodegenFacade.kt mirai-core/src/commonTest/kotlin/testFramework/codegen/ValueDescAnalyzer.kt

+19-35
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
* https://github.com/mamoe/mirai/blob/dev/LICENSE
88
*/
99

10-
package net.mamoe.mirai.internal.utils.codegen
10+
@file:OptIn(ExperimentalStdlibApi::class)
11+
12+
package net.mamoe.mirai.internal.testFramework.codegen
1113

1214
import kotlinx.serialization.Serializable
15+
import net.mamoe.mirai.internal.testFramework.codegen.descriptors.*
1316
import net.mamoe.mirai.utils.cast
1417
import kotlin.reflect.KParameter
1518
import kotlin.reflect.KProperty1
@@ -20,7 +23,10 @@ import kotlin.reflect.full.primaryConstructor
2023
import kotlin.reflect.full.valueParameters
2124
import kotlin.reflect.typeOf
2225

23-
object ConstructorCallCodegenFacade {
26+
object ValueDescAnalyzer {
27+
private val anyType = typeOf<Any>()
28+
29+
2430
/**
2531
* Analyze [value] and give its correspondent [ValueDesc].
2632
*/
@@ -46,17 +52,22 @@ object ConstructorCallCodegenFacade {
4652
return ClassValueDesc(null, value, map)
4753
}
4854

49-
ArrayValueDesc.createOrNull(value, type, null)?.let { return it }
55+
CollectionLikeValueDesc.createOrNull(value, type, null)?.let { return it }
5056
if (value is Collection<*>) {
51-
return CollectionValueDesc(null, value, arrayType = type, elementType = type.arguments.first().type!!)
57+
return CollectionValueDesc(
58+
null,
59+
value,
60+
arrayType = type,
61+
elementType = type.arguments.firstOrNull()?.type ?: anyType
62+
)
5263
} else if (value is Map<*, *>) {
5364
return MapValueDesc(
5465
null,
5566
value.cast(),
5667
value.cast(),
5768
type,
58-
type.arguments.first().type!!,
59-
type.arguments[1].type!!
69+
type.arguments.firstOrNull()?.type ?: anyType,
70+
type.arguments.getOrNull(1)?.type ?: anyType
6071
)
6172
}
6273

@@ -70,36 +81,9 @@ object ConstructorCallCodegenFacade {
7081
else -> PlainValueDesc(null, value.toString(), value)
7182
}
7283
}
73-
74-
/**
75-
* Generate source code to construct the value represented by [desc].
76-
*/
77-
fun generate(desc: ValueDesc, context: CodegenContext = CodegenContext()): String {
78-
if (context.configuration.removeDefaultValues) {
79-
val def = AnalyzeDefaultValuesMappingVisitor()
80-
desc.accept(def)
81-
desc.accept(RemoveDefaultValuesVisitor(def.mappings))
82-
}
83-
84-
ValueCodegen(context).generate(desc)
85-
return context.getResult()
86-
}
87-
88-
fun analyzeAndGenerate(value: Any?, type: KType, context: CodegenContext = CodegenContext()): String {
89-
return generate(analyze(value, type), context)
90-
}
9184
}
9285

9386
@OptIn(ExperimentalStdlibApi::class)
94-
inline fun <reified T> ConstructorCallCodegenFacade.analyze(value: T): ValueDesc {
87+
inline fun <reified T> ValueDescAnalyzer.analyze(value: T): ValueDesc {
9588
return analyze(value, typeOf<T>())
96-
}
97-
98-
@OptIn(ExperimentalStdlibApi::class)
99-
inline fun <reified T> ConstructorCallCodegenFacade.analyzeAndGenerate(
100-
value: T,
101-
context: CodegenContext = CodegenContext()
102-
): String {
103-
return analyzeAndGenerate(value, typeOf<T>(), context)
104-
}
105-
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2019-2021 Mamoe Technologies and contributors.
3+
*
4+
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
5+
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
6+
*
7+
* https://github.com/mamoe/mirai/blob/dev/LICENSE
8+
*/
9+
10+
package net.mamoe.mirai.internal.testFramework.codegen.descriptors
11+
12+
import net.mamoe.mirai.internal.testFramework.codegen.visitor.ValueDescTransformer
13+
import net.mamoe.mirai.internal.testFramework.codegen.visitor.ValueDescVisitor
14+
import kotlin.reflect.KClass
15+
import kotlin.reflect.KParameter
16+
17+
class ClassValueDesc<T : Any>(
18+
override val parent: ValueDesc?,
19+
override val origin: T,
20+
val properties: MutableMap<KParameter, ValueDesc>,
21+
) : ValueDesc {
22+
val type: KClass<out T> by lazy { origin::class }
23+
24+
override fun <D, R> accept(visitor: ValueDescVisitor<D, R>, data: D): R {
25+
return visitor.visitClass(this, data)
26+
}
27+
28+
override fun <D> acceptChildren(visitor: ValueDescVisitor<D, *>, data: D) {
29+
properties.forEach { (_, u) ->
30+
u.accept(visitor, data)
31+
}
32+
}
33+
34+
override fun <D> transformChildren(visitor: ValueDescTransformer<D>, data: D) {
35+
val result = mutableMapOf<KParameter, ValueDesc>()
36+
for (entry in this.properties.entries) {
37+
entry.value.acceptChildren(visitor, data)
38+
val newValue = entry.value.accept(visitor, data)
39+
if (newValue != null) {
40+
result[entry.key] = newValue
41+
}
42+
}
43+
this.properties.clear()
44+
this.properties.putAll(result)
45+
}
46+
}

0 commit comments

Comments
 (0)