Skip to content
Closed
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
2 changes: 1 addition & 1 deletion agent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ dependencies {
// on it keeps the agent's classpath isolated from the host IDE.
implementation(project(":common"))

testImplementation(platform("org.junit:junit-bom:5.11.3"))
testImplementation(platform("org.junit:junit-bom:6.1.3"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,23 @@ public static void agentmain(String agentArgs, Instrumentation inst) {
install(inst);
}

// Byte Buddy refuses class file versions newer than it officially knows (e.g. the
// Java 25 bytecode shipped by the latest JBR) unless experimental mode is enabled.
// Turning it on keeps the agent working on bleeding-edge IDE platforms instead of
// failing every instrumentation with IllegalArgumentException. The literal is
// relocated by the shadow jar together with the rest of net.bytebuddy, so it
// matches the property name Byte Buddy actually reads at runtime.
private static final String BYTE_BUDDY_EXPERIMENTAL_PROPERTY = "net.bytebuddy.experimental";

private static void install(Instrumentation inst) {
if (!INSTALLED.compareAndSet(false, true)) {
AgentLog.info("Agent already installed, skipping duplicate initialization");
return;
}

// must run before any Byte Buddy class file version probing below
enableByteBuddyExperimentalIfUnset();

MarkerAdvice.setWriter(new TraceWriter());
AgentBuilder agent = configureAgent();
List<MarkerInfo> markers = Markers.getAll();
Expand All @@ -50,6 +61,12 @@ private static void install(Instrumentation inst) {
}
}

private static void enableByteBuddyExperimentalIfUnset() {
if (System.getProperty(BYTE_BUDDY_EXPERIMENTAL_PROPERTY) == null) {
System.setProperty(BYTE_BUDDY_EXPERIMENTAL_PROPERTY, "true");
}
}

private static void instrumentMarker(AgentBuilder agent, MarkerInfo marker, Instrumentation inst) {
agent.type(ElementMatchers.named(marker.getClassFqn()))
.transform((builder, typeDescription, classLoader, module, protectionDomain) ->
Expand Down
2 changes: 1 addition & 1 deletion common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ java {
}

dependencies {
testImplementation(platform("org.junit:junit-bom:5.11.3"))
testImplementation(platform("org.junit:junit-bom:6.1.3"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,16 @@
* recurse into itself or instrument non-assertion code. Extending coverage is a
* matter of adding an entry here (the agent, filter, trace format and plugin are
* all marker-agnostic).
*
* <p>Since platform build ~233 the internal calling code increasingly calls
* {@code ThreadingAssertions} directly instead of going through
* {@code ApplicationImpl}. Both classes are instrumented so the agent captures
* markers regardless of which path the platform takes.
*/
public final class Markers {

// --- ApplicationImpl markers (legacy path, still used by plugin code) ---

public static final MarkerInfo SLOW_OPERATION = new MarkerInfo(
"com.intellij.util.SlowOperations",
"assertSlowOperationsAreAllowed",
Expand Down Expand Up @@ -56,7 +63,38 @@ public final class Markers {
"Write Access",
"This code requires write access and must run inside a write action on the EDT (see Application.runWriteAction()).");

private static final List<MarkerInfo> ALL = List.of(SLOW_OPERATION, NON_EDT, EDT, READ_ACCESS, WRITE_ACCESS);
// --- ThreadingAssertions markers (direct path used by platform internals) ---

private static final String THREADING_ASSERTIONS_CLASS =
"com.intellij.util.concurrency.ThreadingAssertions";

public static final MarkerInfo EDT_DIRECT = new MarkerInfo(
THREADING_ASSERTIONS_CLASS,
"assertEventDispatchThread",
"EDT Thread",
"This code must run on the EDT (Event Dispatch Thread). UI operations are allowed.");

public static final MarkerInfo NON_EDT_DIRECT = new MarkerInfo(
THREADING_ASSERTIONS_CLASS,
"assertBackgroundThread",
"Non-EDT Thread",
"This code must NOT run on the EDT. Background/pooled thread required.");

public static final MarkerInfo READ_ACCESS_DIRECT = new MarkerInfo(
THREADING_ASSERTIONS_CLASS,
"assertReadAccess",
"Read Access",
"This code requires read access and must run inside a read action (see Application.runReadAction()).");

public static final MarkerInfo WRITE_ACCESS_DIRECT = new MarkerInfo(
THREADING_ASSERTIONS_CLASS,
"assertWriteAccess",
"Write Access",
"This code requires write access and must run inside a write action on the EDT (see Application.runWriteAction()).");

private static final List<MarkerInfo> ALL = List.of(
SLOW_OPERATION, NON_EDT, EDT, READ_ACCESS, WRITE_ACCESS,
EDT_DIRECT, NON_EDT_DIRECT, READ_ACCESS_DIRECT, WRITE_ACCESS_DIRECT);

public static List<MarkerInfo> getAll() {
return ALL;
Expand Down
9 changes: 4 additions & 5 deletions plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@ repositories {
dependencies {
implementation(project(":common"))
intellijPlatform {
// Target the local test IDE (IntelliJ IDEA Community 2025.1, build 251)
intellijIdeaCommunity("2025.1.1.1")
intellijIdeaUltimate("2025.3.1")
bundledPlugin("org.jetbrains.kotlin")
}

// Pure-logic unit tests (no platform runtime needed)
testImplementation(platform("org.junit:junit-bom:5.11.3"))
testImplementation(platform("org.junit:junit-bom:6.1.3"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
// IntelliJ Platform test harness expects JUnit 4 on the classpath; the vintage
Expand All @@ -35,8 +34,8 @@ dependencies {
intellijPlatform {
pluginConfiguration {
ideaVersion {
sinceBuild = "251"
untilBuild = "251.*"
sinceBuild = "253"
untilBuild = "253.*"
}
}

Expand Down
Loading