using parchment: parameter names & javadoc; use vineflower for source generation #1
|
@ -21,7 +21,7 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.ecorous.esnesnon:mojmap-patcher:1.0.0-SNAPSHOT")
|
implementation("org.ecorous.esnesnon:nonsense-remapper:1.0.0-SNAPSHOT")
|
||||||
implementation("com.google.code.gson:gson:2.10.1")
|
implementation("com.google.code.gson:gson:2.10.1")
|
||||||
implementation("org.vineflower:vineflower:1.10.1")
|
implementation("org.vineflower:vineflower:1.10.1")
|
||||||
testImplementation(kotlin("test"))
|
testImplementation(kotlin("test"))
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
package org.ecorous.esnesnon.gradle
|
package org.ecorous.esnesnon.gradle
|
||||||
|
|
||||||
import net.fabricmc.fernflower.api.IFabricJavadocProvider
|
import net.fabricmc.fernflower.api.IFabricJavadocProvider
|
||||||
|
import org.ecorous.esnesnon.gradle.parchment.ParchmentProvider
|
||||||
import org.ecorous.esnesnon.gradle.vineflower.ParchmentJavadocProvider
|
import org.ecorous.esnesnon.gradle.vineflower.ParchmentJavadocProvider
|
||||||
|
import org.ecorous.esnesnon.gradle.vineflower.RenamingPlugin
|
||||||
import org.gradle.api.Plugin
|
import org.gradle.api.Plugin
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler
|
import org.jetbrains.java.decompiler.main.Fernflower
|
||||||
import org.jetbrains.java.decompiler.main.decompiler.PrintStreamLogger
|
import org.jetbrains.java.decompiler.main.decompiler.PrintStreamLogger
|
||||||
import org.jetbrains.java.decompiler.main.decompiler.SingleFileSaver
|
import org.jetbrains.java.decompiler.main.decompiler.SingleFileSaver
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences
|
||||||
|
import java.io.PrintStream
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.deleteExisting
|
import kotlin.io.path.deleteExisting
|
||||||
import kotlin.io.path.exists
|
import kotlin.io.path.exists
|
||||||
|
@ -47,25 +51,44 @@ class NonsenseGradlePlugin : Plugin<Project> {
|
||||||
group = "nonsense"
|
group = "nonsense"
|
||||||
doFirst {
|
doFirst {
|
||||||
val fileName = remappedGameJarPath.fileName.toString()
|
val fileName = remappedGameJarPath.fileName.toString()
|
||||||
val output = remappedGameJarPath.resolveSibling(fileName.substring(0, fileName.length-4)+"-sources.jar")
|
val output =
|
||||||
|
remappedGameJarPath.resolveSibling(fileName.substring(0, fileName.length - 4) + "-sources.jar")
|
||||||
if (output.exists()) {
|
if (output.exists()) {
|
||||||
println("Output $output already exists, deleting!")
|
println("Output $output already exists, deleting!")
|
||||||
output.deleteExisting()
|
output.deleteExisting()
|
||||||
}
|
}
|
||||||
|
val options = mutableMapOf<String, Any>()
|
||||||
|
if (useParchment) {
|
||||||
|
println("Preparing Parchment...")
|
||||||
|
val parchment = ParchmentProvider.getParchment(
|
||||||
|
minecraftVersion,
|
||||||
|
parchmentVersion,
|
||||||
|
project.gradle.gradleUserHomeDir.resolve("caches/nonsense-gradle/").toPath()
|
||||||
|
)
|
||||||
|
RenamingPlugin.parchment = parchment
|
||||||
|
/*options["variable-renaming"] = "parchment"
|
||||||
|
options["rename-parameters"] = "1"*/
|
||||||
|
options[IFabricJavadocProvider.PROPERTY_NAME] = ParchmentJavadocProvider(parchment)
|
||||||
|
}
|
||||||
println("Decompiling...")
|
println("Decompiling...")
|
||||||
val logger = PrintStreamLogger(System.out)
|
val log = project.rootDir.resolve("vineflower.log").toPath() // TODO temporarily log VF output more verbosely to a separate file to have more debug information
|
||||||
val options = mapOf(
|
Files.deleteIfExists(log)
|
||||||
IFabricJavadocProvider.PROPERTY_NAME to ParchmentJavadocProvider(),
|
val logger = PrintStreamLogger(PrintStream(Files.newOutputStream(log)))
|
||||||
|
options.putAll(
|
||||||
|
mapOf(
|
||||||
IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES to "1",
|
IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES to "1",
|
||||||
IFernflowerPreferences.BYTECODE_SOURCE_MAPPING to "1",
|
IFernflowerPreferences.BYTECODE_SOURCE_MAPPING to "1",
|
||||||
IFernflowerPreferences.REMOVE_SYNTHETIC to "1",
|
IFernflowerPreferences.REMOVE_SYNTHETIC to "1",
|
||||||
IFernflowerPreferences.LOG_LEVEL to "warn",
|
IFernflowerPreferences.LOG_LEVEL to "info", // TODO set to 'warn' before commit/push! (related to the comment above)
|
||||||
IFernflowerPreferences.THREADS to Runtime.getRuntime().availableProcessors().toString(),
|
IFernflowerPreferences.THREADS to Runtime.getRuntime().availableProcessors().toString(),
|
||||||
IFernflowerPreferences.INDENT_STRING to "\t"
|
IFernflowerPreferences.INDENT_STRING to "\t"
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val decomp = BaseDecompiler(SingleFileSaver(output.toFile()),
|
val decomp = Fernflower(
|
||||||
options, logger)
|
SingleFileSaver(output.toFile()),
|
||||||
|
options, logger
|
||||||
|
)
|
||||||
decomp.addSource(remappedGameJarPath.toFile())
|
decomp.addSource(remappedGameJarPath.toFile())
|
||||||
|
|
||||||
decomp.decompileContext()
|
decomp.decompileContext()
|
||||||
|
@ -89,5 +112,7 @@ class NonsenseGradlePlugin : Plugin<Project> {
|
||||||
companion object {
|
companion object {
|
||||||
lateinit var minecraftVersion: String
|
lateinit var minecraftVersion: String
|
||||||
lateinit var remappedGameJarPath: Path
|
lateinit var remappedGameJarPath: Path
|
||||||
|
var useParchment = false
|
||||||
|
lateinit var parchmentVersion: String
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,11 +2,12 @@ package org.ecorous.esnesnon.gradle.ext
|
||||||
|
|
||||||
import org.ecorous.esnesnon.gradle.NonsenseGradlePlugin
|
import org.ecorous.esnesnon.gradle.NonsenseGradlePlugin
|
||||||
import org.ecorous.esnesnon.gradle.VersionChecker
|
import org.ecorous.esnesnon.gradle.VersionChecker
|
||||||
import org.ecorous.esnesnon.mojmap_patcher.MojMapPatcher
|
import org.ecorous.esnesnon.gradle.parchment.ParchmentProvider
|
||||||
|
import org.ecorous.esnesnon.nonsense_remapper.NonsenseRemapper
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import kotlin.io.path.notExists
|
import kotlin.io.path.notExists
|
||||||
|
|
||||||
fun Project.minecraft(version: String) {
|
fun Project.minecraft(version: String): Project { // return self to allow for chaining
|
||||||
if (VersionChecker.validateVersion(version)) {
|
if (VersionChecker.validateVersion(version)) {
|
||||||
NonsenseGradlePlugin.minecraftVersion = version
|
NonsenseGradlePlugin.minecraftVersion = version
|
||||||
println("Valid version! $version")
|
println("Valid version! $version")
|
||||||
|
@ -20,7 +21,7 @@ fun Project.minecraft(version: String) {
|
||||||
NonsenseGradlePlugin.remappedGameJarPath = remappedJar
|
NonsenseGradlePlugin.remappedGameJarPath = remappedJar
|
||||||
println("Time to setup Minecraft!")
|
println("Time to setup Minecraft!")
|
||||||
if (remappedJar.notExists()) {
|
if (remappedJar.notExists()) {
|
||||||
MojMapPatcher.run(version, clientJar, remappedJar, true)
|
NonsenseRemapper.run(version, clientJar, remappedJar, true)
|
||||||
}
|
}
|
||||||
VersionChecker.getDependencies(version){
|
VersionChecker.getDependencies(version){
|
||||||
dependencies.add("implementation", it)
|
dependencies.add("implementation", it)
|
||||||
|
@ -31,4 +32,10 @@ fun Project.minecraft(version: String) {
|
||||||
error("Invalid minecraft version provided: $version")
|
error("Invalid minecraft version provided: $version")
|
||||||
}
|
}
|
||||||
println("Minecraft!")
|
println("Minecraft!")
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Project.parchment(version: String = ParchmentProvider.findLatestValidVersion()) {
|
||||||
|
NonsenseGradlePlugin.useParchment = true
|
||||||
|
NonsenseGradlePlugin.parchmentVersion = version
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
package org.ecorous.esnesnon.gradle.parchment
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import org.ecorous.esnesnon.gradle.NonsenseGradlePlugin
|
||||||
|
import java.net.URI
|
||||||
|
import java.nio.file.FileSystems
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
|
import kotlin.io.path.createParentDirectories
|
||||||
|
import kotlin.io.path.notExists
|
||||||
|
|
||||||
|
object ParchmentProvider {
|
||||||
|
const val PARCHMENT_URL: String = "https://maven.parchmentmc.org/org/parchmentmc/data"
|
||||||
|
|
||||||
|
private fun getParchmentUrl(gameVersion: String): String {
|
||||||
|
return "$PARCHMENT_URL/parchment-$gameVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findParchmentVersion(gameVersion: String): String {
|
||||||
|
val url = getParchmentUrl(gameVersion) + "/maven-metadata.xml"
|
||||||
|
val stream = URI.create(url).toURL().openStream()
|
||||||
|
val document = DocumentBuilderFactory.newInstance()
|
||||||
|
.newDocumentBuilder().parse(stream)
|
||||||
|
stream?.close()
|
||||||
|
return document.getElementsByTagName("release").item(0).textContent
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getParchment(gameVersion: String, cacheDir: Path): Parchment {
|
||||||
|
return getParchment(gameVersion, findParchmentVersion(gameVersion), cacheDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getParchment(gameVersion: String, parchmentVer: String, cacheDir: Path): Parchment {
|
||||||
|
val cachePath = cacheDir.resolve("parchment/$gameVersion/$parchmentVer/parchment-$gameVersion-$parchmentVer.zip")
|
||||||
|
cachePath.createParentDirectories()
|
||||||
|
|
||||||
|
if (cachePath.notExists()){
|
||||||
|
val url = "${getParchmentUrl(gameVersion)}/$parchmentVer/parchment-$gameVersion-$parchmentVer.zip"
|
||||||
|
Files.copy(URI.create(url).toURL().openStream(), cachePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO hash verification
|
||||||
|
FileSystems.newFileSystem(cachePath).use {fs ->
|
||||||
|
val mappings = Files.readString(fs.getPath("parchment.json"))
|
||||||
|
return Gson().fromJson(mappings, Parchment::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findLatestValidVersion(): String {
|
||||||
|
return findForMinecraftVersion(NonsenseGradlePlugin.minecraftVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findForMinecraftVersion(minecraftVersion: String): String {
|
||||||
|
return findParchmentVersion(minecraftVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parchment(val version: String, val packages: List<Package>, val classes: List<Class>?){
|
||||||
|
fun getClass(name: String): Class? {
|
||||||
|
classes?.forEach {
|
||||||
|
if(it.name == name){
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Package(val name: String, val javadoc: List<String>?)
|
||||||
|
class Class(val name: String, val javadoc: List<String>?, val fields: List<Field>?, val methods: List<Method>?){
|
||||||
|
fun getField(name: String, descriptor: String): Field? {
|
||||||
|
fields?.forEach {
|
||||||
|
if(it.name == name && it.descriptor == descriptor){
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMethod(name: String, descriptor: String): Method? {
|
||||||
|
methods?.forEach {
|
||||||
|
if(it.name == name && it.descriptor == descriptor){
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Field(val name: String, val descriptor: String, val javadoc: List<String>?)
|
||||||
|
class Method(val name: String, val descriptor: String, val javadoc: List<String>?, val parameters: List<Parameter>?){
|
||||||
|
fun getParameter(index: Int): Parameter? {
|
||||||
|
parameters?.forEach {
|
||||||
|
if (it.index == index){
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Parameter(val index: Int, val name: String)
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
package org.ecorous.esnesnon.gradle.vineflower
|
package org.ecorous.esnesnon.gradle.vineflower
|
||||||
|
|
||||||
import net.fabricmc.fernflower.api.IFabricJavadocProvider
|
import net.fabricmc.fernflower.api.IFabricJavadocProvider
|
||||||
|
import org.ecorous.esnesnon.gradle.parchment.Parchment
|
||||||
import org.jetbrains.java.decompiler.struct.StructClass
|
import org.jetbrains.java.decompiler.struct.StructClass
|
||||||
import org.jetbrains.java.decompiler.struct.StructField
|
import org.jetbrains.java.decompiler.struct.StructField
|
||||||
import org.jetbrains.java.decompiler.struct.StructMethod
|
import org.jetbrains.java.decompiler.struct.StructMethod
|
||||||
|
|
||||||
class ParchmentJavadocProvider : IFabricJavadocProvider {
|
class ParchmentJavadocProvider(val parchment: Parchment) : IFabricJavadocProvider {
|
||||||
override fun getClassDoc(structClass: StructClass): String {
|
override fun getClassDoc(structClass: StructClass): String? {
|
||||||
return ""
|
return parchment.getClass(structClass.qualifiedName)?.javadoc?.joinToString("\n")
|
||||||
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getFieldDoc(structClass: StructClass, structField: StructField): String {
|
override fun getFieldDoc(structClass: StructClass, structField: StructField): String? {
|
||||||
return ""
|
return parchment.getClass(structClass.qualifiedName)
|
||||||
|
?.getField(structField.name, structField.descriptor)?.javadoc?.joinToString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMethodDoc(structClass: StructClass, structMethod: StructMethod): String {
|
override fun getMethodDoc(structClass: StructClass, structMethod: StructMethod): String? {
|
||||||
return ""
|
return parchment.getClass(structClass.qualifiedName)
|
||||||
|
?.getMethod(structMethod.name, structMethod.descriptor)?.javadoc?.joinToString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
package org.ecorous.esnesnon.gradle.vineflower
|
||||||
|
|
||||||
|
import org.ecorous.esnesnon.gradle.parchment.Parchment
|
||||||
|
import org.jetbrains.java.decompiler.code.CodeConstants
|
||||||
|
import org.jetbrains.java.decompiler.main.DecompilerContext
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IVariableNameProvider
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IVariableNamingFactory
|
||||||
|
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor
|
||||||
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructMethod
|
||||||
|
import org.jetbrains.java.decompiler.struct.gen.CodeType
|
||||||
|
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor
|
||||||
|
import org.jetbrains.java.decompiler.struct.gen.VarType
|
||||||
|
import org.jetbrains.java.decompiler.util.Pair
|
||||||
|
import org.jetbrains.java.decompiler.util.TextUtil
|
||||||
|
|
||||||
|
// Adapted from https://github.com/Vineflower/vineflower/blob/ddf84710f8521ce62d1e3e55a39d300432d6b729/plugins/variable-renaming/src/main/java/org/vineflower/variablerenaming/TinyNameProvider.java
|
||||||
|
class ParchmentNameProvider(private val parchment: Parchment, val method: StructMethod) : IVariableNameProvider {
|
||||||
|
private val parameters: MutableMap<Int, String?> = mutableMapOf()
|
||||||
|
|
||||||
|
private val renameParameters = true
|
||||||
|
private val usedNames: MutableSet<String> = mutableSetOf()
|
||||||
|
|
||||||
|
override fun rename(entries: Map<VarVersionPair, Pair<VarType, String>>): Map<VarVersionPair, String?> {
|
||||||
|
var params = 0
|
||||||
|
if ((this.method.accessFlags and CodeConstants.ACC_STATIC) != CodeConstants.ACC_STATIC) {
|
||||||
|
params++
|
||||||
|
}
|
||||||
|
|
||||||
|
val md = MethodDescriptor.parseDescriptor(this.method.descriptor)
|
||||||
|
for (param in md.params) {
|
||||||
|
params += param.stackSize
|
||||||
|
}
|
||||||
|
|
||||||
|
val keys: MutableList<VarVersionPair> = ArrayList(entries.keys)
|
||||||
|
keys.sortWith { o1: VarVersionPair, o2: VarVersionPair -> if ((o1.`var` != o2.`var`)) o1.`var` - o2.`var` else o1.version - o2.version }
|
||||||
|
|
||||||
|
val result: MutableMap<VarVersionPair, String?> = LinkedHashMap()
|
||||||
|
for (ver in keys) {
|
||||||
|
// note: entries[ver]!!.a is currently null for references that are not parameter definitions. Figure this out. It currently causes errors further down the line
|
||||||
|
// and prevents VF from working correctly.
|
||||||
|
|
||||||
|
val type = cleanType(entries[ver]!!.b)
|
||||||
|
|
||||||
|
if (ver.`var` >= params) {
|
||||||
|
result[ver] = getNewName(
|
||||||
|
Pair.of(
|
||||||
|
entries[ver]!!.a, type
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else if (renameParameters) {
|
||||||
|
result[ver] = parameters.computeIfAbsent(
|
||||||
|
ver.`var`
|
||||||
|
) {
|
||||||
|
parchment.getClass(method.classQualifiedName)?.getMethod(method.name, method.descriptor)
|
||||||
|
?.getParameter(ver.`var`)?.name ?: getNewName(
|
||||||
|
Pair.of(
|
||||||
|
entries[ver]!!.a, type
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNewName(pair: Pair<VarType, String>): String? {
|
||||||
|
val type = pair.a
|
||||||
|
|
||||||
|
usedNames.add(pair.b)
|
||||||
|
|
||||||
|
var increment = true
|
||||||
|
var name: String
|
||||||
|
|
||||||
|
when (type.type) {
|
||||||
|
CodeType.BYTECHAR, CodeType.SHORTCHAR, CodeType.INT -> name = "i"
|
||||||
|
CodeType.LONG -> name = "l"
|
||||||
|
CodeType.BYTE -> name = "b"
|
||||||
|
CodeType.SHORT -> name = "s"
|
||||||
|
CodeType.CHAR -> name = "c"
|
||||||
|
CodeType.FLOAT -> name = "f"
|
||||||
|
CodeType.DOUBLE -> name = "d"
|
||||||
|
CodeType.BOOLEAN -> {
|
||||||
|
name = "bl"
|
||||||
|
increment = false
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeType.OBJECT, CodeType.GENVAR -> {
|
||||||
|
name = pair.b
|
||||||
|
|
||||||
|
// Lowercase first letter
|
||||||
|
if (Character.isUpperCase(name[0])) {
|
||||||
|
name = name[0].lowercaseChar().toString() + name.substring(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.arrayDim > 0 && !name.endsWith("s")) {
|
||||||
|
name += "s"
|
||||||
|
}
|
||||||
|
|
||||||
|
increment = false
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return null
|
||||||
|
}
|
||||||
|
if (increment) {
|
||||||
|
// Must be of length 1
|
||||||
|
var idxStart = name[0].code - 'a'.code
|
||||||
|
while (usedNames.contains(name)) {
|
||||||
|
name = convertToName(idxStart++)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Increment via numbers
|
||||||
|
val oname = name
|
||||||
|
var idx = 0
|
||||||
|
while (usedNames.contains(name)) {
|
||||||
|
name = oname + (++idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TextUtil.isKeyword(name, method.bytecodeVersion, method)) {
|
||||||
|
name += "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
usedNames.add(name)
|
||||||
|
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renameParameter(flags: Int, type: VarType, name: String?, index: Int): String? {
|
||||||
|
var typeName: String
|
||||||
|
DecompilerContext.getImportCollector().lock().use {
|
||||||
|
typeName = ExprProcessor.getCastTypeName(type)
|
||||||
|
}
|
||||||
|
if (!this.renameParameters) {
|
||||||
|
return super.renameParameter(flags, type, name, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters.computeIfAbsent(
|
||||||
|
index
|
||||||
|
) {
|
||||||
|
parchment.getClass(method.classQualifiedName)?.getMethod(method.name, method.descriptor)
|
||||||
|
?.getParameter(index)?.name ?: getNewName(
|
||||||
|
Pair.of(
|
||||||
|
type,
|
||||||
|
cleanType(typeName)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertToName(idx: Int): String {
|
||||||
|
// Convert to base 26
|
||||||
|
val str = idx.toString(26)
|
||||||
|
|
||||||
|
// Remap start of name from '0' to 'a'
|
||||||
|
val res = StringBuilder()
|
||||||
|
for (i in str.length - 1 downTo 0) {
|
||||||
|
var c = str[i]
|
||||||
|
// If we're numerical, remap to lowercase ascii range
|
||||||
|
if (c <= '9') {
|
||||||
|
c = ('a'.code + (c.code - '0'.code)).toChar()
|
||||||
|
} else {
|
||||||
|
// If we're not, simply shift up 10 ascii characters
|
||||||
|
c += 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: idx 26 starts at 'ba', when it should start at 'aa'
|
||||||
|
res.insert(0, c)
|
||||||
|
}
|
||||||
|
return res.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cleanType(type: String): String {
|
||||||
|
var cleaned = type
|
||||||
|
if (cleaned.indexOf('<') != -1) {
|
||||||
|
cleaned = cleaned.substring(0, cleaned.indexOf('<'))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cleaned.indexOf('.') != -1) {
|
||||||
|
cleaned = cleaned.substring(cleaned.lastIndexOf('.') + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cleaned.indexOf('$') != -1) {
|
||||||
|
cleaned = cleaned.substring(cleaned.lastIndexOf('$') + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cleaned = cleaned.replace("\\[]".toRegex(), "")
|
||||||
|
|
||||||
|
return cleaned
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addParentContext(renamer: IVariableNameProvider) {
|
||||||
|
val prov = renamer as ParchmentNameProvider
|
||||||
|
usedNames.addAll(prov.usedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParchmentNameProviderFactory(private val parchment: Parchment) : IVariableNamingFactory {
|
||||||
|
override fun createFactory(structMethod: StructMethod?): IVariableNameProvider {
|
||||||
|
return ParchmentNameProvider(parchment, structMethod!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.ecorous.esnesnon.gradle.vineflower
|
||||||
|
|
||||||
|
import org.ecorous.esnesnon.gradle.parchment.Parchment
|
||||||
|
import org.jetbrains.java.decompiler.api.plugin.Plugin
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IVariableNamingFactory
|
||||||
|
|
||||||
|
class RenamingPlugin : Plugin {
|
||||||
|
override fun id(): String {
|
||||||
|
return "NonsenseGradle"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun description(): String {
|
||||||
|
return "Renaming of parameters using the parchment mappings set"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRenamingFactory(): IVariableNamingFactory {
|
||||||
|
return ParchmentNameProvider.ParchmentNameProviderFactory(parchment)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
lateinit var parchment: Parchment
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.ecorous.esnesnon.gradle.vineflower.RenamingPlugin
|
Loading…
Reference in a new issue
might be nicer in kotlin to do .orElse(null) and use ?.
or at least combine the map calls into one as it seems unnecessary to split them