Enable and apply Ktfmt to xplat/simplesql, xplat/sonar, and xplat/spectrum

Summary: As title.

Reviewed By: zertosh

Differential Revision: D30425160

fbshipit-source-id: c72d270d7cd3f30990aac55e33e8f72d60ed5fe2
This commit is contained in:
Omer Strulovich
2021-08-19 07:27:32 -07:00
committed by Facebook GitHub Bot
parent 8e2a839f9d
commit 1db39b8171
18 changed files with 359 additions and 387 deletions

View File

@@ -14,32 +14,34 @@ import shark.HeapAnalysis
import shark.HeapAnalysisSuccess
class FlipperLeakListener : OnHeapAnalyzedListener {
private val leaks: MutableList<Leak> = mutableListOf()
private val leaks: MutableList<Leak> = mutableListOf()
private val defaultListener = DefaultOnHeapAnalyzedListener.create()
private val defaultListener = DefaultOnHeapAnalyzedListener.create()
override fun onHeapAnalyzed(heapAnalysis: HeapAnalysis) {
leaks.addAll(heapAnalysis.toLeakList())
override fun onHeapAnalyzed(heapAnalysis: HeapAnalysis) {
leaks.addAll(heapAnalysis.toLeakList())
AndroidFlipperClient.getInstanceIfInitialized()?.let { client ->
(client.getPlugin(LeakCanary2FlipperPlugin.ID) as? LeakCanary2FlipperPlugin)
?.reportLeaks(leaks)
}
defaultListener.onHeapAnalyzed(heapAnalysis)
AndroidFlipperClient.getInstanceIfInitialized()?.let { client ->
(client.getPlugin(LeakCanary2FlipperPlugin.ID) as? LeakCanary2FlipperPlugin)?.reportLeaks(
leaks)
}
private fun HeapAnalysis.toLeakList(): List<Leak> {
return if (this is HeapAnalysisSuccess) {
allLeaks.mapNotNull {
if (it.leakTraces.isNotEmpty()) {
it.leakTraces[0].toLeak(it.shortDescription)
} else {
null
}
}.toList()
} else {
emptyList()
}
defaultListener.onHeapAnalyzed(heapAnalysis)
}
private fun HeapAnalysis.toLeakList(): List<Leak> {
return if (this is HeapAnalysisSuccess) {
allLeaks
.mapNotNull {
if (it.leakTraces.isNotEmpty()) {
it.leakTraces[0].toLeak(it.shortDescription)
} else {
null
}
}
.toList()
} else {
emptyList()
}
}
}

View File

@@ -14,40 +14,40 @@ private const val REPORT_LEAK_EVENT = "reportLeak2"
private const val CLEAR_EVENT = "clear"
class LeakCanary2FlipperPlugin : FlipperPlugin {
private val leaks: MutableList<Leak> = mutableListOf()
private val alreadySeenLeakSignatures: MutableSet<String> = mutableSetOf()
private var connection: FlipperConnection? = null
private val leaks: MutableList<Leak> = mutableListOf()
private val alreadySeenLeakSignatures: MutableSet<String> = mutableSetOf()
private var connection: FlipperConnection? = null
override fun getId() = ID
override fun getId() = ID
override fun onConnect(connection: FlipperConnection?) {
this.connection = connection
connection?.receive(CLEAR_EVENT) { _, _ -> leaks.clear() }
sendLeakList()
override fun onConnect(connection: FlipperConnection?) {
this.connection = connection
connection?.receive(CLEAR_EVENT) { _, _ -> leaks.clear() }
sendLeakList()
}
override fun onDisconnect() {
connection = null
}
override fun runInBackground() = false
internal fun reportLeaks(leaks: List<Leak>) {
for (leak in leaks) {
if (leak.signature !in alreadySeenLeakSignatures) {
this.leaks.add(leak)
alreadySeenLeakSignatures.add(leak.signature)
}
}
override fun onDisconnect() {
connection = null
}
sendLeakList()
}
override fun runInBackground() = false
private fun sendLeakList() {
connection?.send(REPORT_LEAK_EVENT, LeakCanary2Report(leaks).toFlipperObject())
}
internal fun reportLeaks(leaks: List<Leak>) {
for (leak in leaks) {
if (leak.signature !in alreadySeenLeakSignatures) {
this.leaks.add(leak)
alreadySeenLeakSignatures.add(leak.signature)
}
}
sendLeakList()
}
private fun sendLeakList() {
connection?.send(REPORT_LEAK_EVENT, LeakCanary2Report(leaks).toFlipperObject())
}
companion object {
const val ID = "LeakCanary"
}
companion object {
const val ID = "LeakCanary"
}
}

View File

@@ -10,135 +10,133 @@ package com.facebook.flipper.plugins.leakcanary2
import com.facebook.flipper.core.FlipperArray
import com.facebook.flipper.core.FlipperObject
import com.facebook.flipper.core.FlipperValue
import java.util.UUID
import shark.LeakTrace
import shark.LeakTraceObject
import java.util.UUID
internal data class LeakCanary2Report(val leaks: List<Leak>) : FlipperValue {
override fun toFlipperObject(): FlipperObject = FlipperObject.Builder()
.put("leaks", leaks.map { it.toFlipperObject() }.toFlipperArray())
.build()
override fun toFlipperObject(): FlipperObject =
FlipperObject.Builder()
.put("leaks", leaks.map { it.toFlipperObject() }.toFlipperArray())
.build()
}
internal data class Leak(
val title: String,
val root: String,
val elements: Map<String, Element>,
val retainedSize: String,
val signature: String,
val details: String
val title: String,
val root: String,
val elements: Map<String, Element>,
val retainedSize: String,
val signature: String,
val details: String
) : FlipperValue {
override fun toFlipperObject(): FlipperObject {
return FlipperObject.Builder()
.put("title", title)
.put("root", root)
.put("elements", elements.toFlipperObject())
.put("retainedSize", retainedSize)
.put("details", details)
.build()
}
override fun toFlipperObject(): FlipperObject {
return FlipperObject.Builder()
.put("title", title)
.put("root", root)
.put("elements", elements.toFlipperObject())
.put("retainedSize", retainedSize)
.put("details", details)
.build()
}
private fun Map<String, FlipperValue>.toFlipperObject(): FlipperObject =
mapValues { it.value.toFlipperObject() }.toFlipperObject()
private fun Map<String, FlipperValue>.toFlipperObject(): FlipperObject =
mapValues { it.value.toFlipperObject() }.toFlipperObject()
@JvmName("toFlipperObjectStringFlipperObject")
private fun Map<String, FlipperObject>.toFlipperObject(): FlipperObject =
asIterable()
.fold(FlipperObject.Builder()) { builder, entry ->
builder.put(entry.key, entry.value)
}
.build()
@JvmName("toFlipperObjectStringFlipperObject")
private fun Map<String, FlipperObject>.toFlipperObject(): FlipperObject =
asIterable()
.fold(FlipperObject.Builder()) { builder, entry -> builder.put(entry.key, entry.value) }
.build()
}
internal fun LeakTrace.toLeak(title: String): Leak {
val elements = getElements()
return Leak(
title = title,
elements = elements.toMap(),
retainedSize = retainedHeapByteSize?.let { "$it bytes" } ?: "unknown size",
signature = signature,
root = elements.first().first,
details = "$this"
)
val elements = getElements()
return Leak(
title = title,
elements = elements.toMap(),
retainedSize = retainedHeapByteSize?.let { "$it bytes" } ?: "unknown size",
signature = signature,
root = elements.first().first,
details = "$this")
}
private fun LeakTrace.getElements(): List<Pair<String, Element>> {
val referenceElements = referencePath.map { reference ->
val id = UUID.randomUUID().toString()
id to Element(id, reference.originObject)
}.toMutableList()
val referenceElements =
referencePath
.map { reference ->
val id = UUID.randomUUID().toString()
id to Element(id, reference.originObject)
}
.toMutableList()
val leakId = UUID.randomUUID().toString()
referenceElements.add(leakId to Element(leakId, leakingObject))
val leakId = UUID.randomUUID().toString()
referenceElements.add(leakId to Element(leakId, leakingObject))
return referenceElements.mapIndexed { index, pair ->
pair.first to if (index == referenceElements.lastIndex) pair.second else pair.second.copy(
children = listOf(referenceElements[index + 1].second.id)
)
}
return referenceElements.mapIndexed { index, pair ->
pair.first to
if (index == referenceElements.lastIndex) pair.second
else pair.second.copy(children = listOf(referenceElements[index + 1].second.id))
}
}
internal data class Element(
val id: String,
val name: String,
val expanded: Boolean = true,
val children: List<String> = emptyList(),
val attributes: List<ElementAttribute>,
val decoration: String = ""
val id: String,
val name: String,
val expanded: Boolean = true,
val children: List<String> = emptyList(),
val attributes: List<ElementAttribute>,
val decoration: String = ""
) : FlipperValue {
constructor(id: String, leakObject: LeakTraceObject) : this(
id = id,
name = "${leakObject.className} (${leakObject.typeName})",
attributes = listOf(
ElementAttribute("leaking", leakObject.leakingStatus.shortName),
ElementAttribute("retaining", leakObject.retaining)
)
)
constructor(
id: String,
leakObject: LeakTraceObject
) : this(
id = id,
name = "${leakObject.className} (${leakObject.typeName})",
attributes =
listOf(
ElementAttribute("leaking", leakObject.leakingStatus.shortName),
ElementAttribute("retaining", leakObject.retaining)))
override fun toFlipperObject(): FlipperObject {
return FlipperObject.Builder()
.put("id", id)
.put("name", name)
.put("expanded", expanded)
.put("children", children.toFlipperArray())
.put("attributes", attributes.toFlipperArray())
.put("data", EMPTY_FLIPPER_OBJECT)
.put("decoration", decoration)
.put("extraInfo", EMPTY_FLIPPER_OBJECT)
.build()
}
override fun toFlipperObject(): FlipperObject {
return FlipperObject.Builder()
.put("id", id)
.put("name", name)
.put("expanded", expanded)
.put("children", children.toFlipperArray())
.put("attributes", attributes.toFlipperArray())
.put("data", EMPTY_FLIPPER_OBJECT)
.put("decoration", decoration)
.put("extraInfo", EMPTY_FLIPPER_OBJECT)
.build()
}
@JvmName("toFlipperArrayFlipperValue")
private fun Iterable<FlipperValue>.toFlipperArray(): FlipperArray =
map { it.toFlipperObject() }.toFlipperArray()
@JvmName("toFlipperArrayFlipperValue")
private fun Iterable<FlipperValue>.toFlipperArray(): FlipperArray =
map { it.toFlipperObject() }.toFlipperArray()
@JvmName("toFlipperArrayString")
private fun Iterable<String>.toFlipperArray(): FlipperArray =
fold(FlipperArray.Builder()) { builder, row -> builder.put(row) }.build()
@JvmName("toFlipperArrayString")
private fun Iterable<String>.toFlipperArray(): FlipperArray =
fold(FlipperArray.Builder()) { builder, row -> builder.put(row) }.build()
}
internal fun Iterable<FlipperObject>.toFlipperArray(): FlipperArray =
fold(FlipperArray.Builder()) { builder, row -> builder.put(row) }.build()
fold(FlipperArray.Builder()) { builder, row -> builder.put(row) }.build()
private val LeakTraceObject.LeakingStatus.shortName: String
get() = when (this) {
get() =
when (this) {
LeakTraceObject.LeakingStatus.NOT_LEAKING -> "N"
LeakTraceObject.LeakingStatus.LEAKING -> "Y"
LeakTraceObject.LeakingStatus.UNKNOWN -> "?"
}
}
private val LeakTraceObject.retaining: String
get() = retainedHeapByteSize?.let { "$it bytes ($retainedObjectCount objects)" } ?: "unknown"
get() = retainedHeapByteSize?.let { "$it bytes ($retainedObjectCount objects)" } ?: "unknown"
private val EMPTY_FLIPPER_OBJECT = FlipperObject.Builder().build()
data class ElementAttribute(
val name: String,
val value: String
) : FlipperValue {
override fun toFlipperObject(): FlipperObject {
return FlipperObject.Builder()
.put("name", name)
.put("value", value)
.build()
}
data class ElementAttribute(val name: String, val value: String) : FlipperValue {
override fun toFlipperObject(): FlipperObject {
return FlipperObject.Builder().put("name", name).put("value", value).build()
}
}

View File

@@ -16,35 +16,32 @@ import com.facebook.flipper.plugins.retrofit2protobuf.adapter.RetrofitServiceToG
import com.facebook.flipper.plugins.retrofit2protobuf.model.CallNestedMessagesPayload
object SendProtobufToFlipperFromRetrofit {
operator fun invoke(baseUrl: String, service: Class<*>) {
getNetworkPlugin()?.addProtobufDefinitions(
baseUrl,
generateProtobufDefinitions(service).toFlipperArray()
)
}
operator fun invoke(baseUrl: String, service: Class<*>) {
getNetworkPlugin()
?.addProtobufDefinitions(baseUrl, generateProtobufDefinitions(service).toFlipperArray())
}
private fun getNetworkPlugin(): NetworkFlipperPlugin? {
return AndroidFlipperClient.getInstanceIfInitialized()?.let { client ->
client.getPlugin(NetworkFlipperPlugin.ID) as? NetworkFlipperPlugin
}
private fun getNetworkPlugin(): NetworkFlipperPlugin? {
return AndroidFlipperClient.getInstanceIfInitialized()?.let { client ->
client.getPlugin(NetworkFlipperPlugin.ID) as? NetworkFlipperPlugin
}
}
private fun generateProtobufDefinitions(service: Class<*>): List<CallNestedMessagesPayload> {
return RetrofitServiceToGenericCallDefinitions(service).let { definitions ->
GenericCallDefinitionsToMessageDefinitionsIfProtobuf(definitions)
}.let { messages ->
messages.map {
CallNestedMessagesPayload(
path = it.path,
method = it.method,
requestMessageFullName = it.requestMessageFullName,
requestDefinitions = it.requestModel,
responseMessageFullName = it.responseMessageFullName,
responseDefinitions = it.responseModel
)
}
private fun generateProtobufDefinitions(service: Class<*>): List<CallNestedMessagesPayload> {
return RetrofitServiceToGenericCallDefinitions(service)
.let { definitions -> GenericCallDefinitionsToMessageDefinitionsIfProtobuf(definitions) }
.let { messages ->
messages.map {
CallNestedMessagesPayload(
path = it.path,
method = it.method,
requestMessageFullName = it.requestMessageFullName,
requestDefinitions = it.requestModel,
responseMessageFullName = it.responseMessageFullName,
responseDefinitions = it.responseModel)
}
}
}
}
}
private fun Iterable<FlipperValue>.toFlipperArray(): FlipperArray =

View File

@@ -12,23 +12,22 @@ import com.facebook.flipper.plugins.retrofit2protobuf.model.GenericCallDefinitio
import me.haroldmartin.protobufjavatoprotobufjs.ProtobufGeneratedJavaToProtobufJs
internal object GenericCallDefinitionsToMessageDefinitionsIfProtobuf {
operator fun invoke(callDefinitions: List<GenericCallDefinition>): List<FullNamedMessagesCallDefinition> {
return callDefinitions.mapNotNull { definition ->
val responseRootAndMessages = definition.responseType?.let {
ProtobufGeneratedJavaToProtobufJs(it)
}
val requestRootAndMessages = definition.requestType?.let {
ProtobufGeneratedJavaToProtobufJs(it)
}
operator fun invoke(
callDefinitions: List<GenericCallDefinition>
): List<FullNamedMessagesCallDefinition> {
return callDefinitions.mapNotNull { definition ->
val responseRootAndMessages =
definition.responseType?.let { ProtobufGeneratedJavaToProtobufJs(it) }
val requestRootAndMessages =
definition.requestType?.let { ProtobufGeneratedJavaToProtobufJs(it) }
FullNamedMessagesCallDefinition(
path = definition.path,
method = definition.method,
responseMessageFullName = responseRootAndMessages?.rootFullName,
responseModel = responseRootAndMessages?.descriptors,
requestMessageFullName = requestRootAndMessages?.rootFullName,
requestModel = requestRootAndMessages?.descriptors
)
}
FullNamedMessagesCallDefinition(
path = definition.path,
method = definition.method,
responseMessageFullName = responseRootAndMessages?.rootFullName,
responseModel = responseRootAndMessages?.descriptors,
requestMessageFullName = requestRootAndMessages?.rootFullName,
requestModel = requestRootAndMessages?.descriptors)
}
}
}

View File

@@ -13,65 +13,64 @@ import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
internal object RetrofitServiceToGenericCallDefinitions {
@Suppress("LoopWithTooManyJumpStatements")
operator fun invoke(service: Class<*>): List<GenericCallDefinition> {
val methodToProtobufDefinition = mutableListOf<GenericCallDefinition>()
for (method in service.declaredMethods) {
val responseType = method.innerGenericReturnClass ?: continue
val (path, httpMethod) = method.annotations.urlPathAndMethod ?: continue
methodToProtobufDefinition.add(
GenericCallDefinition(
path = path,
method = httpMethod,
responseType = responseType,
requestType = method.requestBodyType
)
)
}
return methodToProtobufDefinition
@Suppress("LoopWithTooManyJumpStatements")
operator fun invoke(service: Class<*>): List<GenericCallDefinition> {
val methodToProtobufDefinition = mutableListOf<GenericCallDefinition>()
for (method in service.declaredMethods) {
val responseType = method.innerGenericReturnClass ?: continue
val (path, httpMethod) = method.annotations.urlPathAndMethod ?: continue
methodToProtobufDefinition.add(
GenericCallDefinition(
path = path,
method = httpMethod,
responseType = responseType,
requestType = method.requestBodyType))
}
return methodToProtobufDefinition
}
}
private val Array<Annotation>.urlPathAndMethod: Pair<String, String>?
get() {
var path: Pair<String, String>? = null
for (a in this) {
path = when (a.annotationClass) {
retrofit2.http.DELETE::class -> (a as retrofit2.http.DELETE).value to "DELETE"
retrofit2.http.GET::class -> (a as retrofit2.http.GET).value to "GET"
retrofit2.http.HEAD::class -> (a as retrofit2.http.HEAD).value to "HEAD"
retrofit2.http.OPTIONS::class -> (a as retrofit2.http.OPTIONS).value to "OPTIONS"
retrofit2.http.PATCH::class -> (a as retrofit2.http.PATCH).value to "PATCH"
retrofit2.http.POST::class -> (a as retrofit2.http.POST).value to "POST"
retrofit2.http.PUT::class -> (a as retrofit2.http.PUT).value to "PUT"
else -> null
}
if (path != null) break
}
return path
get() {
var path: Pair<String, String>? = null
for (a in this) {
path =
when (a.annotationClass) {
retrofit2.http.DELETE::class -> (a as retrofit2.http.DELETE).value to "DELETE"
retrofit2.http.GET::class -> (a as retrofit2.http.GET).value to "GET"
retrofit2.http.HEAD::class -> (a as retrofit2.http.HEAD).value to "HEAD"
retrofit2.http.OPTIONS::class -> (a as retrofit2.http.OPTIONS).value to "OPTIONS"
retrofit2.http.PATCH::class -> (a as retrofit2.http.PATCH).value to "PATCH"
retrofit2.http.POST::class -> (a as retrofit2.http.POST).value to "POST"
retrofit2.http.PUT::class -> (a as retrofit2.http.PUT).value to "PUT"
else -> null
}
if (path != null) break
}
return path
}
private val Method.requestBodyType: Class<*>?
get() {
parameterAnnotations.forEachIndexed { index, annotations ->
annotations.forEach { annotation ->
if (annotation.annotationClass == retrofit2.http.Body::class) {
return parameterTypes[index]
}
}
get() {
parameterAnnotations.forEachIndexed { index, annotations ->
annotations.forEach { annotation ->
if (annotation.annotationClass == retrofit2.http.Body::class) {
return parameterTypes[index]
}
return null
}
}
return null
}
private val Method.innerGenericReturnClass: Class<*>?
get() = (genericReturnType as? ParameterizedType)?.innerGenericType as? Class<*>
get() = (genericReturnType as? ParameterizedType)?.innerGenericType as? Class<*>
private val ParameterizedType?.innerGenericType: Type?
get() {
val innerType = this?.actualTypeArguments?.get(0)
return if (innerType is ParameterizedType) {
innerType.innerGenericType
} else {
innerType
}
get() {
val innerType = this?.actualTypeArguments?.get(0)
return if (innerType is ParameterizedType) {
innerType.innerGenericType
} else {
innerType
}
}

View File

@@ -19,29 +19,30 @@ internal data class CallNestedMessagesPayload(
val responseMessageFullName: String?,
val responseDefinitions: Map<String, Any>?
) : FlipperValue {
override fun toFlipperObject(): FlipperObject {
return FlipperObject.Builder()
.put("path", path)
.put("method", method)
.put("requestMessageFullName", requestMessageFullName)
.put("requestDefinitions", requestDefinitions?.toFlipperObject())
.put("responseMessageFullName", responseMessageFullName)
.put("responseDefinitions", responseDefinitions?.toFlipperObject())
.build()
}
override fun toFlipperObject(): FlipperObject {
return FlipperObject.Builder()
.put("path", path)
.put("method", method)
.put("requestMessageFullName", requestMessageFullName)
.put("requestDefinitions", requestDefinitions?.toFlipperObject())
.put("responseMessageFullName", responseMessageFullName)
.put("responseDefinitions", responseDefinitions?.toFlipperObject())
.build()
}
}
private fun Map<*, *>.toFlipperObject(): FlipperObject {
val builder = FlipperObject.Builder()
this.forEach { (key, value) ->
val castValue = when (value) {
is Map<*, *> -> value.toFlipperObject()
is Iterable<*> -> value.toFlipperArray()
else -> value
val builder = FlipperObject.Builder()
this.forEach { (key, value) ->
val castValue =
when (value) {
is Map<*, *> -> value.toFlipperObject()
is Iterable<*> -> value.toFlipperArray()
else -> value
}
builder.put(key as String, castValue)
}
return builder.build()
builder.put(key as String, castValue)
}
return builder.build()
}
private fun Iterable<*>.toFlipperArray(): FlipperArray =