Skip to content
This repository was archived by the owner on Mar 26, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ subprojects {
repositories {
mavenCentral()
maven("https://www.jetbrains.com/intellij-repository/releases")
maven("https://www.jetbrains.com/intellij-repository/snapshots")
maven("https://cache-redirector.jetbrains.com/intellij-dependencies")
}

Expand Down
21 changes: 21 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,33 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import java.util.*

plugins {
`kotlin-dsl`
}

repositories {
mavenCentral()
maven("https://www.jetbrains.com/intellij-repository/releases")
maven("https://www.jetbrains.com/intellij-repository/snapshots")
maven("https://cache-redirector.jetbrains.com/intellij-dependencies")
}


val gradleProperties = Properties()
val gradlePropertiesFile = project.file("../gradle.properties")
if (gradlePropertiesFile.canRead()) {
gradleProperties.load(gradlePropertiesFile.inputStream())
}

val intellijPlatformVersion: String by gradleProperties

dependencies {
implementation("com.jetbrains.intellij.platform:core:$intellijPlatformVersion") {
exclude(group = "org.jetbrains.kotlin") // cannot find these dependencies
}
}

kotlin {
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ dnsjavaVersion=3.4.3
electronVersion=^16.0.6
electronPackagerVersion=^15.1.0
gradleMkdocsPluginVersion=2.2.0
intellijPlatformVersion=213.6461.23
intellijMarkdownPluginVersion=213.5744.223
intellijPlatformVersion=213.6777.52
intellijMarkdownPluginVersion=213.6777.52
intellijJcefVersion=89.0.12-g2b76680-chromium-89.0.4389.90-api-1.6
istanbulInstrumenterLoaderVersion=3.0.1
javassistVersion=3.28.0-GA
Expand Down
3 changes: 3 additions & 0 deletions projector-agent-common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ publishToSpace("java")

val javassistVersion: String by project
val kotestVersion: String by project
val kotlinVersion: String by project

dependencies {
implementation(project(":projector-util-loading"))

implementation(kotlin("reflect", kotlinVersion))
implementation("org.javassist:javassist:$javassistVersion")
testImplementation("io.kotest:kotest-assertions-core:$kotestVersion")
testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,127 @@
package org.jetbrains.projector.agent.common

import javassist.*
import org.jetbrains.projector.util.loading.ProjectorClassLoader
import org.jetbrains.projector.util.loading.UseProjectorLoader
import java.lang.IllegalArgumentException
import java.lang.reflect.Constructor
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import kotlin.reflect.KFunction
import kotlin.reflect.full.createType
import kotlin.reflect.jvm.javaConstructor
import kotlin.reflect.jvm.javaMethod

internal fun getClassFromClassfileBuffer(pool: ClassPool, className: String, classfileBuffer: ByteArray): CtClass {
pool.insertClassPath(ByteArrayClassPath(className, classfileBuffer))
return pool.get(className).apply(CtClass::defrost)
}

private val currentClassPool: ClassPool by lazy { ClassPool().apply { appendClassPath(LoaderClassPath(object {}.javaClass.classLoader)) } }
public val projectorClassPool: ClassPool by lazy { ClassPool().apply { appendClassPath(LoaderClassPath(ProjectorClassLoader.instance)) } }

private fun CtClass.getDeclaredMethodImpl(name: String, classPool: ClassPool, params: Array<out Class<*>>): CtMethod =
getDeclaredMethod(name, params.map { classPool[it.name] }.toTypedArray())

public fun CtClass.getDeclaredMethod(name: String, vararg params: Class<*>): CtMethod =
getDeclaredMethodImpl(name, currentClassPool, params)
getDeclaredMethodImpl(name, projectorClassPool, params)

private fun CtClass.getDeclaredConstructorImpl(classPool: ClassPool, params: Array<out Class<*>>): CtConstructor =
getDeclaredConstructor(params.map { classPool[it.name] }.toTypedArray())

public fun CtClass.getDeclaredConstructor(vararg params: Class<*>): CtConstructor =
getDeclaredConstructorImpl(projectorClassPool, params)

public inline operator fun <reified T> ClassPool.invoke(): CtClass = this[T::class.java.name]

public fun Method.toGetDeclaredMethodFormat(): String {

//val parameterClasses = parameterTypes.joinToString(", ") { "${it.kotlin.javaObjectType.name}.class" }
val parameterClasses = parameterTypes.joinToString(", ") { "${it.name}.class" }
val parametersString = "new Class[] { $parameterClasses }"

return "\"$name\", $parametersString"
}

public fun Constructor<*>.toGetDeclaredMethodFormat(): String {
val parameterClasses = parameterTypes.joinToString(", ") { "${it.name}.class" }
return "new Class[] { $parameterClasses }"
}

public fun loadClassWithProjectorLoader(clazz: Class<*>): String = loadClassWithProjectorLoader(clazz.name, true)

private fun loadClassWithProjectorLoader(className: String, trim: Boolean): String = """
$commonClassLoadCode
.loadClass("$className")
""".let { if (!trim) it.trimIndent() else it }

private val unitType by lazy { Unit::class.createType() }

public fun <T : KFunction<*>> T.getJavaCallString(
vararg params: String,
finishedExpression: Boolean = this.returnType == unitType,
autoCast: Boolean = true,
): String {

val mainPart = when {
javaMethod != null -> getJavaCallString(javaMethod!!, autoCast, *params)
javaConstructor != null -> getJavaCallString(javaConstructor!!, autoCast, *params)
else -> throw IllegalArgumentException("Cannot convert Kotlin function $this to Java method")
}

return if (finishedExpression)
"""
{
$mainPart;
}
""".trimIndent()
else mainPart
}

private fun getJavaCallString(asJavaMethod: Method, cast: Boolean = true, vararg params: String): String {

val isStatic = Modifier.isStatic(asJavaMethod.modifiers)
val instance = if (isStatic) "null" else params.first()
val otherParams = if (isStatic) params.toList() else params.drop(1)

require(otherParams.size == asJavaMethod.parameterCount) {
"Cannot create Java method call string: expected ${asJavaMethod.parameterCount} parameters, got ${otherParams.size}"
}

val castString = if (!cast || asJavaMethod.returnType == Void.TYPE) "" else "(${asJavaMethod.returnType.objectType.name})"

return """
($castString ${loadClassWithProjectorLoader(asJavaMethod.declaringClass.name, false)}
.getDeclaredMethod(${asJavaMethod.toGetDeclaredMethodFormat()})
.invoke($instance, new Object[] { ${otherParams.joinToString(", ")} }))
""".trimIndent()
}

private fun getJavaCallString(asJavaCtor: Constructor<*>, cast: Boolean = true, vararg params: String): String {
require(params.size == asJavaCtor.parameterCount) {
"Cannot create Java method call string: expected ${asJavaCtor.parameterCount} parameters, got ${params.size}"
}

val castString = if (!cast) "" else "(${asJavaCtor.declaringClass.name})"

return """
($castString ${loadClassWithProjectorLoader(asJavaCtor.declaringClass)}
.getDeclaredConstructor(${asJavaCtor.toGetDeclaredMethodFormat()})
.newInstance(new Object[] { ${params.joinToString(", ")} }))
""".trimIndent()
}

private val Class<*>.objectType get() = kotlin.javaObjectType

public const val assign: String = "${'$'}_ = "

private val PROJECTOR_LOADER_CLASS_NAME: String = ProjectorClassLoader::class.java.name

private val PROJECTOR_LOADER_INSTANCE_GETTER_NAME: String = ProjectorClassLoader.Companion::instance.getter.javaMethod!!.name

private val commonClassLoadCode = """
((ClassLoader) ClassLoader
.getSystemClassLoader()
.loadClass("$PROJECTOR_LOADER_CLASS_NAME")
.getDeclaredMethod("$PROJECTOR_LOADER_INSTANCE_GETTER_NAME", new Class[0])
.invoke(null, new Object[0]))
""".trimIndent()
1 change: 1 addition & 0 deletions projector-agent-ij-injector/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ val kotestVersion: String by project

dependencies {
implementation(project(":projector-agent-common"))
implementation(project(":projector-common"))
implementation(project(":projector-ij-common"))
implementation(project(":projector-util-loading"))
implementation(project(":projector-util-logging"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package org.jetbrains.projector.agent.ijInjector

import org.jetbrains.projector.agent.init.IjArgs
import org.jetbrains.projector.ij.jcef.isCefAvailable
import org.jetbrains.projector.util.loading.UseProjectorLoader
import java.lang.instrument.Instrumentation

Expand All @@ -34,7 +35,9 @@ internal object IjInjector {
class AgentParameters(
val isAgent: Boolean,
val markdownPanelClassName: String,
)
) {
val jcefTransformerInUse by lazy { isCefAvailable() }
}

private fun parametersFromArgs(args: Map<String, String>): AgentParameters {

Expand All @@ -52,6 +55,7 @@ internal object IjInjector {
val transformers = listOf(
IjLigaturesDisablerTransformer,
IjMdTransformer,
IjJcefTransformer,
IjBrowserUtilTransformer,
IjUiUtilsTransformer,
IjFastNodeCellRendererTransformer,
Expand Down
Loading