Do not resolve services in static initializers in IDEKotlinBinaryClassCache, KT-33973

This commit is contained in:
Vladimir Dolzhenko
2019-09-24 16:47:49 +02:00
parent 6f739db3b1
commit a8c72b7e84
12 changed files with 52 additions and 26 deletions
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.idea.core.formatter;
import com.intellij.application.options.CodeStyle; import com.intellij.application.options.CodeStyle;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.Service;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.WriteExternalException;
@@ -33,8 +35,6 @@ import org.jetbrains.kotlin.idea.util.ReflectionUtil;
import static com.intellij.util.ReflectionUtil.copyFields; import static com.intellij.util.ReflectionUtil.copyFields;
public class KotlinCodeStyleSettings extends CustomCodeStyleSettings { public class KotlinCodeStyleSettings extends CustomCodeStyleSettings {
public static final KotlinCodeStyleSettings DEFAULT = new KotlinCodeStyleSettings(new CodeStyleSettings());
public final PackageEntryTable PACKAGES_TO_USE_STAR_IMPORTS = new PackageEntryTable(); public final PackageEntryTable PACKAGES_TO_USE_STAR_IMPORTS = new PackageEntryTable();
public boolean SPACE_AROUND_RANGE = false; public boolean SPACE_AROUND_RANGE = false;
public boolean SPACE_BEFORE_TYPE_COLON = false; public boolean SPACE_BEFORE_TYPE_COLON = false;
@@ -180,4 +180,13 @@ public class KotlinCodeStyleSettings extends CustomCodeStyleSettings {
copyFrom(settingsAgainstPreviousDefaults); copyFrom(settingsAgainstPreviousDefaults);
} }
} }
public static KotlinCodeStyleSettings defaultSettings() {
return ServiceManager.getService(KotlinCodeStyleSettingsHolder.class).defaultSettings;
}
@Service
private static final class KotlinCodeStyleSettingsHolder {
private final KotlinCodeStyleSettings defaultSettings = new KotlinCodeStyleSettings(new CodeStyleSettings());
}
} }
@@ -16,4 +16,4 @@ fun ASTBlock.requireNode() = node ?: error("ASTBlock.getNode() returned null")
/** /**
* Can be removed with all usages after moving master to 1.3 with new default code style settings. * Can be removed with all usages after moving master to 1.3 with new default code style settings.
*/ */
val isDefaultOfficialCodeStyle by lazy { !KotlinCodeStyleSettings.DEFAULT.CONTINUATION_INDENT_FOR_CHAINED_CALLS } val isDefaultOfficialCodeStyle by lazy { !KotlinCodeStyleSettings.defaultSettings().CONTINUATION_INDENT_FOR_CHAINED_CALLS }
@@ -17,7 +17,9 @@
package org.jetbrains.kotlin.idea.caches package org.jetbrains.kotlin.idea.caches
import com.intellij.ide.highlighter.JavaClassFileType import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.components.service
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileWithId import com.intellij.openapi.vfs.VirtualFileWithId
@@ -28,7 +30,8 @@ import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
object IDEKotlinBinaryClassCache { @Service
class IDEKotlinBinaryClassCache {
class KotlinBinaryClassHeaderData( class KotlinBinaryClassHeaderData(
val classId: ClassId, val classId: ClassId,
val kind: KotlinClassHeader.Kind, val kind: KotlinClassHeader.Kind,
@@ -132,4 +135,8 @@ object IDEKotlinBinaryClassCache {
return null return null
} }
companion object {
fun getInstance(): IDEKotlinBinaryClassCache = service()
}
} }
@@ -41,9 +41,10 @@ val KEY = Key.create<IsKotlinBinary>(KOTLIN_COMPILED_FILE_ATTRIBUTE)
* Checks if this file is a compiled Kotlin class file ABI-compatible with the current plugin * Checks if this file is a compiled Kotlin class file ABI-compatible with the current plugin
*/ */
fun isKotlinWithCompatibleAbiVersion(file: VirtualFile): Boolean { fun isKotlinWithCompatibleAbiVersion(file: VirtualFile): Boolean {
if (!IDEKotlinBinaryClassCache.isKotlinJvmCompiledFile(file)) return false val ideKotlinBinaryClassCache = IDEKotlinBinaryClassCache.getInstance()
if (!ideKotlinBinaryClassCache.isKotlinJvmCompiledFile(file)) return false
val kotlinClass = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file) val kotlinClass = ideKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file)
return kotlinClass != null && kotlinClass.metadataVersion.isCompatible() return kotlinClass != null && kotlinClass.metadataVersion.isCompatible()
} }
@@ -57,7 +58,9 @@ fun isKotlinInternalCompiledFile(file: VirtualFile, fileContent: ByteArray? = nu
return false return false
} }
if (!IDEKotlinBinaryClassCache.isKotlinJvmCompiledFile(file, fileContent)) { val ideKotlinBinaryClassCache = IDEKotlinBinaryClassCache.getInstance()
if (!ideKotlinBinaryClassCache.isKotlinJvmCompiledFile(file, fileContent)) {
return false return false
} }
@@ -80,7 +83,7 @@ fun isKotlinInternalCompiledFile(file: VirtualFile, fileContent: ByteArray? = nu
return true return true
} }
val header = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file, fileContent) ?: return false val header = ideKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file, fileContent) ?: return false
if (header.classId.isLocal) return true if (header.classId.isLocal) return true
return header.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS || return header.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS ||
@@ -43,8 +43,9 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
import java.io.InputStream import java.io.InputStream
fun DeserializerForClassfileDecompiler(classFile: VirtualFile): DeserializerForClassfileDecompiler { fun DeserializerForClassfileDecompiler(classFile: VirtualFile): DeserializerForClassfileDecompiler {
val kotlinClassHeaderInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(classFile) val kotlinClassHeaderInfo =
?: error("Decompiled data factory shouldn't be called on an unsupported file: " + classFile) IDEKotlinBinaryClassCache.getInstance().getKotlinBinaryClassHeaderData(classFile)
?: error("Decompiled data factory shouldn't be called on an unsupported file: $classFile")
val packageFqName = kotlinClassHeaderInfo.classId.packageFqName val packageFqName = kotlinClassHeaderInfo.classId.packageFqName
return DeserializerForClassfileDecompiler(classFile.parent!!, packageFqName) return DeserializerForClassfileDecompiler(classFile.parent!!, packageFqName)
} }
@@ -119,7 +120,7 @@ class DirectoryBasedClassFinder(
val targetName = classId.relativeClassName.pathSegments().joinToString("$", postfix = ".class") val targetName = classId.relativeClassName.pathSegments().joinToString("$", postfix = ".class")
val virtualFile = packageDirectory.findChild(targetName) val virtualFile = packageDirectory.findChild(targetName)
if (virtualFile != null && isKotlinWithCompatibleAbiVersion(virtualFile)) { if (virtualFile != null && isKotlinWithCompatibleAbiVersion(virtualFile)) {
return IDEKotlinBinaryClassCache.getKotlinBinaryClass(virtualFile)?.let(::KotlinClass) return IDEKotlinBinaryClassCache.getInstance().getKotlinBinaryClass(virtualFile)?.let(::KotlinClass)
} }
return null return null
} }
@@ -40,7 +40,7 @@ import org.jetbrains.kotlin.types.isFlexible
class KotlinClassFileDecompiler : ClassFileDecompilers.Full() { class KotlinClassFileDecompiler : ClassFileDecompilers.Full() {
private val stubBuilder = KotlinClsStubBuilder() private val stubBuilder = KotlinClsStubBuilder()
override fun accepts(file: VirtualFile) = IDEKotlinBinaryClassCache.isKotlinJvmCompiledFile(file) override fun accepts(file: VirtualFile) = IDEKotlinBinaryClassCache.getInstance().isKotlinJvmCompiledFile(file)
override fun getStubBuilder() = stubBuilder override fun getStubBuilder() = stubBuilder
@@ -67,8 +67,9 @@ fun buildDecompiledTextForClassFile(
classFile: VirtualFile, classFile: VirtualFile,
resolver: ResolverForDecompiler = DeserializerForClassfileDecompiler(classFile) resolver: ResolverForDecompiler = DeserializerForClassfileDecompiler(classFile)
): DecompiledText { ): DecompiledText {
val classHeader = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(classFile) val classHeader =
?: error("Decompiled data factory shouldn't be called on an unsupported file: " + classFile) IDEKotlinBinaryClassCache.getInstance().getKotlinBinaryClassHeaderData(classFile)
?: error("Decompiled data factory shouldn't be called on an unsupported file: $classFile")
val classId = classHeader.classId val classId = classHeader.classId
@@ -59,7 +59,8 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
} }
private fun doBuildFileStub(file: VirtualFile, fileContent: ByteArray): PsiFileStub<KtFile>? { private fun doBuildFileStub(file: VirtualFile, fileContent: ByteArray): PsiFileStub<KtFile>? {
val kotlinClass = IDEKotlinBinaryClassCache.getKotlinBinaryClass(file, fileContent) ?: error("Can't find binary class for Kotlin file: $file") val kotlinClass = IDEKotlinBinaryClassCache.getInstance().getKotlinBinaryClass(file, fileContent)
?: error("Can't find binary class for Kotlin file: $file")
val header = kotlinClass.classHeader val header = kotlinClass.classHeader
val classId = kotlinClass.classId val classId = kotlinClass.classId
val packageFqName = header.packageName?.let { FqName(it) } ?: classId.packageFqName val packageFqName = header.packageName?.let { FqName(it) } ?: classId.packageFqName
@@ -92,7 +92,7 @@ object KotlinClassFileIndex : KotlinFileIndexBase<KotlinClassFileIndex>(KotlinCl
private val VERSION = 3 private val VERSION = 3
private val INDEXER = indexer { fileContent -> private val INDEXER = indexer { fileContent ->
val headerInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(fileContent.file, fileContent.content) val headerInfo = IDEKotlinBinaryClassCache.getInstance().getKotlinBinaryClassHeaderData(fileContent.file, fileContent.content)
if (headerInfo != null && headerInfo.metadataVersion.isCompatible()) headerInfo.classId.asSingleFqName() else null if (headerInfo != null && headerInfo.metadataVersion.isCompatible()) headerInfo.classId.asSingleFqName() else null
} }
} }
@@ -70,9 +70,9 @@ class ImportSettingsPanel(private val commonSettings: CodeStyleSettings) : JPane
private val starImportPackageTable = ImportLayoutPanel.createTableForPackageEntries(starImportPackageEntryTable, dummyImportLayoutPanel) private val starImportPackageTable = ImportLayoutPanel.createTableForPackageEntries(starImportPackageEntryTable, dummyImportLayoutPanel)
private val nameCountToUseStarImportSelector = NameCountToUseStarImportSelector( private val nameCountToUseStarImportSelector = NameCountToUseStarImportSelector(
"Top-level Symbols", KotlinCodeStyleSettings.DEFAULT.NAME_COUNT_TO_USE_STAR_IMPORT) "Top-level Symbols", KotlinCodeStyleSettings.defaultSettings().NAME_COUNT_TO_USE_STAR_IMPORT)
private val nameCountToUseStarImportForMembersSelector = NameCountToUseStarImportSelector( private val nameCountToUseStarImportForMembersSelector = NameCountToUseStarImportSelector(
"Java Statics and Enum Members", KotlinCodeStyleSettings.DEFAULT.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS) "Java Statics and Enum Members", KotlinCodeStyleSettings.defaultSettings().NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS)
init { init {
layout = BorderLayout() layout = BorderLayout()
@@ -42,14 +42,18 @@ class KotlinFormatterUsageCollector {
private val KOTLIN_DEFAULT_COMMON = KotlinLanguageCodeStyleSettingsProvider().defaultCommonSettings private val KOTLIN_DEFAULT_COMMON = KotlinLanguageCodeStyleSettingsProvider().defaultCommonSettings
.also { KotlinStyleGuideCodeStyle.applyToCommonSettings(it) } .also { KotlinStyleGuideCodeStyle.applyToCommonSettings(it) }
private val KOTLIN_DEFAULT_CUSTOM = KotlinCodeStyleSettings.DEFAULT.cloneSettings() private val KOTLIN_DEFAULT_CUSTOM by lazy {
.also { KotlinStyleGuideCodeStyle.applyToKotlinCustomSettings(it) } KotlinCodeStyleSettings.defaultSettings().cloneSettings()
.also { KotlinStyleGuideCodeStyle.applyToKotlinCustomSettings(it) }
}
private val KOTLIN_OBSOLETE_DEFAULT_COMMON = KotlinLanguageCodeStyleSettingsProvider().defaultCommonSettings private val KOTLIN_OBSOLETE_DEFAULT_COMMON = KotlinLanguageCodeStyleSettingsProvider().defaultCommonSettings
.also { KotlinObsoleteCodeStyle.applyToCommonSettings(it) } .also { KotlinObsoleteCodeStyle.applyToCommonSettings(it) }
private val KOTLIN_OBSOLETE_DEFAULT_CUSTOM = KotlinCodeStyleSettings.DEFAULT.cloneSettings() private val KOTLIN_OBSOLETE_DEFAULT_CUSTOM by lazy {
.also { KotlinObsoleteCodeStyle.applyToKotlinCustomSettings(it) } KotlinCodeStyleSettings.defaultSettings().cloneSettings()
.also { KotlinObsoleteCodeStyle.applyToKotlinCustomSettings(it) }
}
fun getKotlinFormatterKind(project: Project): KotlinFormatterKind { fun getKotlinFormatterKind(project: Project): KotlinFormatterKind {
val isProject = CodeStyleSettingsManager.getInstance(project).USE_PER_PROJECT_SETTINGS val isProject = CodeStyleSettingsManager.getInstance(project).USE_PER_PROJECT_SETTINGS
@@ -60,11 +64,11 @@ class KotlinFormatterUsageCollector {
val kotlinCustomSettings = settings.kotlinCustomSettings val kotlinCustomSettings = settings.kotlinCustomSettings
val isDefaultKotlinCommonSettings = kotlinCommonSettings == KotlinLanguageCodeStyleSettingsProvider().defaultCommonSettings val isDefaultKotlinCommonSettings = kotlinCommonSettings == KotlinLanguageCodeStyleSettingsProvider().defaultCommonSettings
val isDefaultKotlinCustomSettings = kotlinCustomSettings == KotlinCodeStyleSettings.DEFAULT val isDefaultKotlinCustomSettings = kotlinCustomSettings == KotlinCodeStyleSettings.defaultSettings()
if (isDefaultKotlinCommonSettings && isDefaultKotlinCustomSettings) { if (isDefaultKotlinCommonSettings && isDefaultKotlinCustomSettings) {
return if (isDefaultOfficialCodeStyle) { return if (isDefaultOfficialCodeStyle) {
paired(IDEA_OFFICIAL_DEFAULT, isProject) paired(KotlinFormatterKind.IDEA_OFFICIAL_DEFAULT, isProject)
} else { } else {
paired(IDEA_DEFAULT, isProject) paired(IDEA_DEFAULT, isProject)
} }
@@ -16,7 +16,7 @@ import org.junit.Assert
abstract class AbstractInternalCompiledClassesTest : KotlinLightCodeInsightFixtureTestCase() { abstract class AbstractInternalCompiledClassesTest : KotlinLightCodeInsightFixtureTestCase() {
private fun isFileWithHeader(predicate: (IDEKotlinBinaryClassCache.KotlinBinaryClassHeaderData, ClassId) -> Boolean) : VirtualFile.() -> Boolean = { private fun isFileWithHeader(predicate: (IDEKotlinBinaryClassCache.KotlinBinaryClassHeaderData, ClassId) -> Boolean) : VirtualFile.() -> Boolean = {
val info = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(this) val info = IDEKotlinBinaryClassCache.getInstance().getKotlinBinaryClassHeaderData(this)
info != null && predicate(info, info.classId) info != null && predicate(info, info.classId)
} }
@@ -63,7 +63,7 @@ class BuiltInDecompilerConsistencyTest : KotlinLightCodeInsightFixtureTestCase()
for (className in classFiles) { for (className in classFiles) {
val classFile = dir.findChild(className + "." + JavaClassFileType.INSTANCE.defaultExtension)!! val classFile = dir.findChild(className + "." + JavaClassFileType.INSTANCE.defaultExtension)!!
val fileContent = FileContentImpl.createByFile(classFile) val fileContent = FileContentImpl.createByFile(classFile)
if (IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(fileContent.file) == null) continue if (IDEKotlinBinaryClassCache.getInstance().getKotlinBinaryClassHeaderData(fileContent.file) == null) continue
val fileStub = classFileDecompiler.stubBuilder.buildFileStub(fileContent) ?: continue val fileStub = classFileDecompiler.stubBuilder.buildFileStub(fileContent) ?: continue
val classStub = fileStub.findChildStubByType(KtClassElementType.getStubType(false)) ?: continue val classStub = fileStub.findChildStubByType(KtClassElementType.getStubType(false)) ?: continue
val classFqName = classStub.getFqName()!! val classFqName = classStub.getFqName()!!