Fix class loading deadlock in Error diagnostic classes

Because of non-trivial initialization logic, Errors/ErrorsJvm/etc.
  are prone to class loading issues. This commit prevents them by
  preloading all error on plugin initialization step.
This commit is contained in:
Yan Zhulanow
2020-02-12 21:46:10 +09:00
parent 2f34bc88dc
commit 1c945430bc
3 changed files with 69 additions and 0 deletions
@@ -32,8 +32,13 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.searches.IndexPatternSearch;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter;
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTodoSearcher;
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm;
import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative;
import org.jetbrains.kotlin.utils.PathUtil;
import static org.jetbrains.kotlin.idea.TestResourceBundleKt.registerAdditionalResourceBundleInTests;
@@ -50,6 +55,7 @@ public class PluginStartupActivity implements StartupActivity.DumbAware {
}
registerPathVariable();
initializeDiagnostics();
try {
// API added in 15.0.2
@@ -88,6 +94,23 @@ public class PluginStartupActivity implements StartupActivity.DumbAware {
});
}
/*
Concurrent access to Errors may lead to the class loading dead lock because of non-trivial initialization in Errors.
As a work-around, all Error classes are initialized beforehand.
It doesn't matter what exact diagnostic factories are used here.
*/
private static void initializeDiagnostics() {
consumeFactory(Errors.DEPRECATION);
consumeFactory(ErrorsJvm.ACCIDENTAL_OVERRIDE);
consumeFactory(ErrorsJs.CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE);
consumeFactory(ErrorsNative.INCOMPATIBLE_THROWS_INHERITED);
}
private static void consumeFactory(DiagnosticFactory<?> factory) {
//noinspection ResultOfMethodCallIgnored
factory.getClass();
}
private static void registerPathVariable() {
PathMacros macros = PathMacros.getInstance();
macros.setMacro(KOTLIN_BUNDLED, PathUtil.getKotlinPathsForIdeaPlugin().getHomePath().getPath());
@@ -29,8 +29,13 @@ import com.intellij.openapi.updateSettings.impl.UpdateChecker;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.searches.IndexPatternSearch;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter;
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTodoSearcher;
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm;
import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative;
import org.jetbrains.kotlin.utils.PathUtil;
import java.io.File;
@@ -60,6 +65,7 @@ public class PluginStartupComponent implements BaseComponent {
}
registerPathVariable();
initializeDiagnostics();
try {
// API added in 15.0.2
@@ -89,6 +95,23 @@ public class PluginStartupComponent implements BaseComponent {
//KotlinSdkType.Companion.setUpIfNeeded();
}
/*
Concurrent access to Errors may lead to the class loading dead lock because of non-trivial initialization in Errors.
As a work-around, all Error classes are initialized beforehand.
It doesn't matter what exact diagnostic factories are used here.
*/
private static void initializeDiagnostics() {
consumeFactory(Errors.DEPRECATION);
consumeFactory(ErrorsJvm.ACCIDENTAL_OVERRIDE);
consumeFactory(ErrorsJs.CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE);
consumeFactory(ErrorsNative.INCOMPATIBLE_THROWS_INHERITED);
}
private static void consumeFactory(DiagnosticFactory<?> factory) {
//noinspection ResultOfMethodCallIgnored
factory.getClass();
}
private static void registerPathVariable() {
PathMacros macros = PathMacros.getInstance();
macros.setMacro(KOTLIN_BUNDLED, PathUtil.getKotlinPathsForIdeaPlugin().getHomePath().getPath());
@@ -29,8 +29,13 @@ import com.intellij.openapi.updateSettings.impl.UpdateChecker;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.searches.IndexPatternSearch;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter;
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTodoSearcher;
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm;
import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative;
import org.jetbrains.kotlin.utils.PathUtil;
import java.io.File;
@@ -60,6 +65,7 @@ public class PluginStartupComponent implements BaseComponent {
}
registerPathVariable();
initializeDiagnostics();
try {
// API added in 15.0.2
@@ -89,6 +95,23 @@ public class PluginStartupComponent implements BaseComponent {
//KotlinSdkType.Companion.setUpIfNeeded();
}
/*
Concurrent access to Errors may lead to the class loading dead lock because of non-trivial initialization in Errors.
As a work-around, all Error classes are initialized beforehand.
It doesn't matter what exact diagnostic factories are used here.
*/
private static void initializeDiagnostics() {
consumeFactory(Errors.DEPRECATION);
consumeFactory(ErrorsJvm.ACCIDENTAL_OVERRIDE);
consumeFactory(ErrorsJs.CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE);
consumeFactory(ErrorsNative.INCOMPATIBLE_THROWS_INHERITED);
}
private static void consumeFactory(DiagnosticFactory<?> factory) {
//noinspection ResultOfMethodCallIgnored
factory.getClass();
}
private static void registerPathVariable() {
PathMacros macros = PathMacros.getInstance();
macros.setMacro(KOTLIN_BUNDLED, PathUtil.getKotlinPathsForIdeaPlugin().getHomePath().getPath());