Faster startup avoiding unnecessary class loading
This commit is contained in:
committed by
Vladimir Dolzhenko
parent
f7d0be980b
commit
c853ae49a2
@@ -41,8 +41,8 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.KtWhenEntry
|
import org.jetbrains.kotlin.psi.KtWhenEntry
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementType
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementType
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
|
||||||
|
|
||||||
class KotlinParserDefinition : ParserDefinition {
|
class KotlinParserDefinition : ParserDefinition {
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ class KotlinParserDefinition : ParserDefinition {
|
|||||||
|
|
||||||
override fun createParser(project: Project): PsiParser = KotlinParser(project)
|
override fun createParser(project: Project): PsiParser = KotlinParser(project)
|
||||||
|
|
||||||
override fun getFileNodeType(): IFileElementType = KtStubElementTypes.FILE
|
override fun getFileNodeType(): IFileElementType = KtFileElementType.INSTANCE
|
||||||
|
|
||||||
override fun getWhitespaceTokens(): TokenSet = KtTokens.WHITESPACES
|
override fun getWhitespaceTokens(): TokenSet = KtTokens.WHITESPACES
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ import java.io.IOException;
|
|||||||
public class KtFileElementType extends IStubFileElementType<KotlinFileStub> {
|
public class KtFileElementType extends IStubFileElementType<KotlinFileStub> {
|
||||||
private static final String NAME = "kotlin.FILE";
|
private static final String NAME = "kotlin.FILE";
|
||||||
|
|
||||||
|
public static KtFileElementType INSTANCE = new KtFileElementType();
|
||||||
|
|
||||||
public KtFileElementType() {
|
public KtFileElementType() {
|
||||||
super(NAME, KotlinLanguage.INSTANCE);
|
super(NAME, KotlinLanguage.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import com.intellij.psi.tree.TokenSet;
|
|||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
|
|
||||||
public interface KtStubElementTypes {
|
public interface KtStubElementTypes {
|
||||||
KtFileElementType FILE = new KtFileElementType();
|
KtFileElementType FILE = KtFileElementType.INSTANCE;
|
||||||
|
|
||||||
KtClassElementType CLASS = new KtClassElementType("CLASS");
|
KtClassElementType CLASS = new KtClassElementType("CLASS");
|
||||||
KtFunctionElementType FUNCTION = new KtFunctionElementType("FUN");
|
KtFunctionElementType FUNCTION = new KtFunctionElementType("FUN");
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class KotlinPathsFromHomeDir(
|
|||||||
) : KotlinPathsFromBaseDirectory(File(homePath, "lib")) {
|
) : KotlinPathsFromBaseDirectory(File(homePath, "lib")) {
|
||||||
|
|
||||||
// TODO: extend when needed
|
// TODO: extend when needed
|
||||||
val libsWithSources = setOf(KotlinPaths.Jar.StdLib, KotlinPaths.Jar.JsStdLib)
|
val libsWithSources: Set<KotlinPaths.Jar> by lazy { setOf(KotlinPaths.Jar.StdLib, KotlinPaths.Jar.JsStdLib) }
|
||||||
|
|
||||||
override fun sourcesJar(jar: KotlinPaths.Jar): File? = if (jar in libsWithSources) super.sourcesJar(jar) else null
|
override fun sourcesJar(jar: KotlinPaths.Jar): File? = if (jar in libsWithSources) super.sourcesJar(jar) else null
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-7
@@ -32,8 +32,8 @@ import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
|||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
|
|
||||||
class KotlinBuiltInDecompiler : KotlinMetadataDecompiler<BuiltInsBinaryVersion>(
|
class KotlinBuiltInDecompiler : KotlinMetadataDecompiler<BuiltInsBinaryVersion>(
|
||||||
KotlinBuiltInFileType, BuiltInSerializerProtocol,
|
KotlinBuiltInFileType, { BuiltInSerializerProtocol },
|
||||||
FlexibleTypeDeserializer.ThrowException, BuiltInsBinaryVersion.INSTANCE, BuiltInsBinaryVersion.INVALID_VERSION,
|
FlexibleTypeDeserializer.ThrowException, { BuiltInsBinaryVersion.INSTANCE }, { BuiltInsBinaryVersion.INVALID_VERSION },
|
||||||
KotlinStubVersions.BUILTIN_STUB_VERSION
|
KotlinStubVersions.BUILTIN_STUB_VERSION
|
||||||
) {
|
) {
|
||||||
override fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? {
|
override fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? {
|
||||||
@@ -42,10 +42,10 @@ class KotlinBuiltInDecompiler : KotlinMetadataDecompiler<BuiltInsBinaryVersion>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class BuiltInDefinitionFile(
|
class BuiltInDefinitionFile(
|
||||||
proto: ProtoBuf.PackageFragment,
|
proto: ProtoBuf.PackageFragment,
|
||||||
version: BuiltInsBinaryVersion,
|
version: BuiltInsBinaryVersion,
|
||||||
val packageDirectory: VirtualFile,
|
val packageDirectory: VirtualFile,
|
||||||
val isMetadata: Boolean
|
val isMetadata: Boolean
|
||||||
) : FileWithMetadata.Compatible(proto, version, BuiltInSerializerProtocol) {
|
) : FileWithMetadata.Compatible(proto, version, BuiltInSerializerProtocol) {
|
||||||
override val classesToDecompile: List<ProtoBuf.Class>
|
override val classesToDecompile: List<ProtoBuf.Class>
|
||||||
get() = super.classesToDecompile.let { classes ->
|
get() = super.classesToDecompile.let { classes ->
|
||||||
@@ -77,7 +77,8 @@ class BuiltInDefinitionFile(
|
|||||||
BuiltInDefinitionFile(proto, version, file.parent, file.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION)
|
BuiltInDefinitionFile(proto, version, file.parent, file.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION)
|
||||||
val packageProto = result.proto.`package`
|
val packageProto = result.proto.`package`
|
||||||
if (result.classesToDecompile.isEmpty() &&
|
if (result.classesToDecompile.isEmpty() &&
|
||||||
packageProto.typeAliasCount == 0 && packageProto.functionCount == 0 && packageProto.propertyCount == 0) {
|
packageProto.typeAliasCount == 0 && packageProto.functionCount == 0 && packageProto.propertyCount == 0
|
||||||
|
) {
|
||||||
// No declarations to decompile: should skip this file
|
// No declarations to decompile: should skip this file
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-18
@@ -40,29 +40,31 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
abstract class KotlinMetadataDecompiler<out V : BinaryVersion>(
|
abstract class KotlinMetadataDecompiler<out V : BinaryVersion>(
|
||||||
private val fileType: FileType,
|
private val fileType: FileType,
|
||||||
private val serializerProtocol: SerializerExtensionProtocol,
|
private val serializerProtocol: () -> SerializerExtensionProtocol,
|
||||||
private val flexibleTypeDeserializer: FlexibleTypeDeserializer,
|
private val flexibleTypeDeserializer: FlexibleTypeDeserializer,
|
||||||
private val expectedBinaryVersion: V,
|
private val expectedBinaryVersion: () -> V,
|
||||||
private val invalidBinaryVersion: V,
|
private val invalidBinaryVersion: () -> V,
|
||||||
stubVersion: Int
|
stubVersion: Int
|
||||||
) : ClassFileDecompilers.Full() {
|
) : ClassFileDecompilers.Full() {
|
||||||
private val stubBuilder = KotlinMetadataStubBuilder(stubVersion, fileType, serializerProtocol, ::readFileSafely)
|
private val metadataStubBuilder: KotlinMetadataStubBuilder =
|
||||||
|
KotlinMetadataStubBuilder(stubVersion, fileType, serializerProtocol, ::readFileSafely)
|
||||||
|
|
||||||
private val renderer = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
private val renderer: DescriptorRenderer by lazy {
|
||||||
|
DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
||||||
|
}
|
||||||
|
|
||||||
abstract fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata?
|
abstract fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata?
|
||||||
|
|
||||||
override fun accepts(file: VirtualFile) = file.fileType == fileType
|
override fun accepts(file: VirtualFile) = file.fileType == fileType
|
||||||
|
|
||||||
override fun getStubBuilder() = stubBuilder
|
override fun getStubBuilder() = metadataStubBuilder
|
||||||
|
|
||||||
override fun createFileViewProvider(file: VirtualFile, manager: PsiManager, physical: Boolean): FileViewProvider {
|
override fun createFileViewProvider(file: VirtualFile, manager: PsiManager, physical: Boolean): FileViewProvider {
|
||||||
return KotlinDecompiledFileViewProvider(manager, file, physical) { provider ->
|
return KotlinDecompiledFileViewProvider(manager, file, physical) { provider ->
|
||||||
if (readFileSafely(provider.virtualFile) == null) {
|
if (readFileSafely(provider.virtualFile) == null) {
|
||||||
null
|
null
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
KtDecompiledFile(provider, this::buildDecompiledText)
|
KtDecompiledFile(provider, this::buildDecompiledText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,16 +93,16 @@ abstract class KotlinMetadataDecompiler<out V : BinaryVersion>(
|
|||||||
|
|
||||||
return when (file) {
|
return when (file) {
|
||||||
null -> {
|
null -> {
|
||||||
createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion, invalidBinaryVersion)
|
createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion(), invalidBinaryVersion())
|
||||||
}
|
}
|
||||||
is FileWithMetadata.Incompatible -> {
|
is FileWithMetadata.Incompatible -> {
|
||||||
createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion, file.version)
|
createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion(), file.version)
|
||||||
}
|
}
|
||||||
is FileWithMetadata.Compatible -> {
|
is FileWithMetadata.Compatible -> {
|
||||||
val packageFqName = file.packageFqName
|
val packageFqName = file.packageFqName
|
||||||
val resolver = KotlinMetadataDeserializerForDecompiler(
|
val resolver = KotlinMetadataDeserializerForDecompiler(
|
||||||
packageFqName, file.proto, file.nameResolver, file.version,
|
packageFqName, file.proto, file.nameResolver, file.version,
|
||||||
serializerProtocol, flexibleTypeDeserializer
|
serializerProtocol(), flexibleTypeDeserializer
|
||||||
)
|
)
|
||||||
val declarations = arrayListOf<DeclarationDescriptor>()
|
val declarations = arrayListOf<DeclarationDescriptor>()
|
||||||
declarations.addAll(resolver.resolveDeclarationsInFacade(packageFqName))
|
declarations.addAll(resolver.resolveDeclarationsInFacade(packageFqName))
|
||||||
@@ -126,9 +128,9 @@ sealed class FileWithMetadata {
|
|||||||
val packageFqName = FqName(nameResolver.getPackageFqName(proto.`package`.getExtension(serializerProtocol.packageFqName)))
|
val packageFqName = FqName(nameResolver.getPackageFqName(proto.`package`.getExtension(serializerProtocol.packageFqName)))
|
||||||
|
|
||||||
open val classesToDecompile: List<ProtoBuf.Class> =
|
open val classesToDecompile: List<ProtoBuf.Class> =
|
||||||
proto.class_List.filter { proto ->
|
proto.class_List.filter { proto ->
|
||||||
val classId = nameResolver.getClassId(proto.fqName)
|
val classId = nameResolver.getClassId(proto.fqName)
|
||||||
!classId.isNestedClass && classId !in ClassDeserializer.BLACK_LIST
|
!classId.isNestedClass && classId !in ClassDeserializer.BLACK_LIST
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
|||||||
open class KotlinMetadataStubBuilder(
|
open class KotlinMetadataStubBuilder(
|
||||||
private val version: Int,
|
private val version: Int,
|
||||||
private val fileType: FileType,
|
private val fileType: FileType,
|
||||||
private val serializerProtocol: SerializerExtensionProtocol,
|
private val serializerProtocol: () -> SerializerExtensionProtocol,
|
||||||
private val readFile: (VirtualFile, ByteArray) -> FileWithMetadata?
|
private val readFile: (VirtualFile, ByteArray) -> FileWithMetadata?
|
||||||
) : ClsStubBuilder() {
|
) : ClsStubBuilder() {
|
||||||
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + version
|
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + version
|
||||||
@@ -52,7 +52,7 @@ open class KotlinMetadataStubBuilder(
|
|||||||
val nameResolver = file.nameResolver
|
val nameResolver = file.nameResolver
|
||||||
val components = ClsStubBuilderComponents(
|
val components = ClsStubBuilderComponents(
|
||||||
ProtoBasedClassDataFinder(file.proto, nameResolver, file.version),
|
ProtoBasedClassDataFinder(file.proto, nameResolver, file.version),
|
||||||
AnnotationLoaderForStubBuilderImpl(serializerProtocol),
|
AnnotationLoaderForStubBuilderImpl(serializerProtocol()),
|
||||||
virtualFile
|
virtualFile
|
||||||
)
|
)
|
||||||
val context = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
|
val context = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
|
||||||
|
|||||||
+2
-2
@@ -28,8 +28,8 @@ import org.jetbrains.kotlin.utils.JsMetadataVersion
|
|||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
|
|
||||||
class KotlinJavaScriptMetaFileDecompiler : KotlinMetadataDecompiler<JsMetadataVersion>(
|
class KotlinJavaScriptMetaFileDecompiler : KotlinMetadataDecompiler<JsMetadataVersion>(
|
||||||
KotlinJavaScriptMetaFileType, JsSerializerProtocol, DynamicTypeDeserializer,
|
KotlinJavaScriptMetaFileType, { JsSerializerProtocol }, DynamicTypeDeserializer,
|
||||||
JsMetadataVersion.INSTANCE, JsMetadataVersion.INVALID_VERSION, KotlinStubVersions.JS_STUB_VERSION
|
{ JsMetadataVersion.INSTANCE }, { JsMetadataVersion.INVALID_VERSION }, KotlinStubVersions.JS_STUB_VERSION
|
||||||
) {
|
) {
|
||||||
override fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? {
|
override fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? {
|
||||||
val stream = ByteArrayInputStream(bytes)
|
val stream = ByteArrayInputStream(bytes)
|
||||||
|
|||||||
+3
-3
@@ -15,9 +15,9 @@ import org.jetbrains.kotlin.serialization.konan.KonanSerializerProtocol
|
|||||||
import org.jetbrains.kotlin.serialization.konan.NullFlexibleTypeDeserializer
|
import org.jetbrains.kotlin.serialization.konan.NullFlexibleTypeDeserializer
|
||||||
|
|
||||||
class KotlinNativeMetadataDecompiler : KotlinNativeMetadataDecompilerBase<KotlinNativeMetadataVersion>(
|
class KotlinNativeMetadataDecompiler : KotlinNativeMetadataDecompilerBase<KotlinNativeMetadataVersion>(
|
||||||
KotlinNativeMetaFileType, KonanSerializerProtocol, NullFlexibleTypeDeserializer,
|
KotlinNativeMetaFileType, { KonanSerializerProtocol }, NullFlexibleTypeDeserializer,
|
||||||
KotlinNativeMetadataVersion.DEFAULT_INSTANCE,
|
{ KotlinNativeMetadataVersion.DEFAULT_INSTANCE },
|
||||||
KotlinNativeMetadataVersion.INVALID_VERSION,
|
{ KotlinNativeMetadataVersion.INVALID_VERSION },
|
||||||
KotlinNativeMetaFileType.STUB_VERSION
|
KotlinNativeMetaFileType.STUB_VERSION
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|||||||
+11
-9
@@ -30,14 +30,14 @@ import java.io.IOException
|
|||||||
|
|
||||||
abstract class KotlinNativeMetadataDecompilerBase<out V : BinaryVersion>(
|
abstract class KotlinNativeMetadataDecompilerBase<out V : BinaryVersion>(
|
||||||
private val fileType: FileType,
|
private val fileType: FileType,
|
||||||
private val serializerProtocol: SerializerExtensionProtocol,
|
private val serializerProtocol: () -> SerializerExtensionProtocol,
|
||||||
private val flexibleTypeDeserializer: FlexibleTypeDeserializer,
|
private val flexibleTypeDeserializer: FlexibleTypeDeserializer,
|
||||||
private val expectedBinaryVersion: V,
|
private val expectedBinaryVersion: () -> V,
|
||||||
private val invalidBinaryVersion: V,
|
private val invalidBinaryVersion: () -> V,
|
||||||
stubVersion: Int
|
stubVersion: Int
|
||||||
) : ClassFileDecompilers.Full() {
|
) : ClassFileDecompilers.Full() {
|
||||||
|
|
||||||
private val stubBuilder =
|
private val metadataStubBuilder: KotlinNativeMetadataStubBuilder =
|
||||||
KotlinNativeMetadataStubBuilder(
|
KotlinNativeMetadataStubBuilder(
|
||||||
stubVersion,
|
stubVersion,
|
||||||
fileType,
|
fileType,
|
||||||
@@ -45,13 +45,15 @@ abstract class KotlinNativeMetadataDecompilerBase<out V : BinaryVersion>(
|
|||||||
::readFileSafely
|
::readFileSafely
|
||||||
)
|
)
|
||||||
|
|
||||||
private val renderer = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
private val renderer: DescriptorRenderer by lazy {
|
||||||
|
DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract fun doReadFile(file: VirtualFile): FileWithMetadata?
|
protected abstract fun doReadFile(file: VirtualFile): FileWithMetadata?
|
||||||
|
|
||||||
override fun accepts(file: VirtualFile) = file.fileType == fileType
|
override fun accepts(file: VirtualFile) = file.fileType == fileType
|
||||||
|
|
||||||
override fun getStubBuilder() = stubBuilder
|
override fun getStubBuilder() = metadataStubBuilder
|
||||||
|
|
||||||
override fun createFileViewProvider(file: VirtualFile, manager: PsiManager, physical: Boolean) =
|
override fun createFileViewProvider(file: VirtualFile, manager: PsiManager, physical: Boolean) =
|
||||||
KotlinDecompiledFileViewProvider(manager, file, physical) { provider ->
|
KotlinDecompiledFileViewProvider(manager, file, physical) { provider ->
|
||||||
@@ -81,14 +83,14 @@ abstract class KotlinNativeMetadataDecompilerBase<out V : BinaryVersion>(
|
|||||||
val file = readFileSafely(virtualFile)
|
val file = readFileSafely(virtualFile)
|
||||||
|
|
||||||
return when (file) {
|
return when (file) {
|
||||||
is FileWithMetadata.Incompatible -> createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion, file.version)
|
is FileWithMetadata.Incompatible -> createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion(), file.version)
|
||||||
is FileWithMetadata.Compatible -> decompiledText(
|
is FileWithMetadata.Compatible -> decompiledText(
|
||||||
file,
|
file,
|
||||||
serializerProtocol,
|
serializerProtocol(),
|
||||||
flexibleTypeDeserializer,
|
flexibleTypeDeserializer,
|
||||||
renderer
|
renderer
|
||||||
)
|
)
|
||||||
null -> createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion, invalidBinaryVersion)
|
null -> createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion(), invalidBinaryVersion())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.serialization.konan.NullFlexibleTypeDeserializer
|
|||||||
open class KotlinNativeMetadataStubBuilder(
|
open class KotlinNativeMetadataStubBuilder(
|
||||||
private val version: Int,
|
private val version: Int,
|
||||||
private val fileType: FileType,
|
private val fileType: FileType,
|
||||||
private val serializerProtocol: SerializerExtensionProtocol,
|
private val serializerProtocol: () -> SerializerExtensionProtocol,
|
||||||
private val readFile: (VirtualFile) -> FileWithMetadata?
|
private val readFile: (VirtualFile) -> FileWithMetadata?
|
||||||
) : ClsStubBuilder() {
|
) : ClsStubBuilder() {
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ open class KotlinNativeMetadataStubBuilder(
|
|||||||
val renderer = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
val renderer = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
|
||||||
val ktFileText = decompiledText(
|
val ktFileText = decompiledText(
|
||||||
file,
|
file,
|
||||||
serializerProtocol,
|
serializerProtocol(),
|
||||||
NullFlexibleTypeDeserializer,
|
NullFlexibleTypeDeserializer,
|
||||||
renderer
|
renderer
|
||||||
)
|
)
|
||||||
|
|||||||
+8
-6
@@ -24,12 +24,14 @@ import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.KotlinTraceExpress
|
|||||||
|
|
||||||
class JavaStandardLibrarySupportProvider : LibrarySupportProvider {
|
class JavaStandardLibrarySupportProvider : LibrarySupportProvider {
|
||||||
private companion object {
|
private companion object {
|
||||||
val builder = TerminatedChainBuilder(
|
val builder: TerminatedChainBuilder by lazy {
|
||||||
KotlinChainTransformerImpl(JavaStreamChainTypeExtractor()),
|
TerminatedChainBuilder(
|
||||||
StandardLibraryCallChecker(PackageBasedCallChecker("java.util.stream"))
|
KotlinChainTransformerImpl(JavaStreamChainTypeExtractor()),
|
||||||
)
|
StandardLibraryCallChecker(PackageBasedCallChecker("java.util.stream"))
|
||||||
val support = StandardLibrarySupport()
|
)
|
||||||
val dsl = DslImpl(KotlinStatementFactory(JavaPeekCallFactory()))
|
}
|
||||||
|
val support: StandardLibrarySupport by lazy { StandardLibrarySupport() }
|
||||||
|
val dsl: DslImpl by lazy { DslImpl(KotlinStatementFactory(JavaPeekCallFactory())) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLanguageId(): String = KotlinLanguage.INSTANCE.id
|
override fun getLanguageId(): String = KotlinLanguage.INSTANCE.id
|
||||||
|
|||||||
@@ -47,20 +47,22 @@ import org.jetbrains.kotlin.kdoc.lexer.KDocTokens;
|
|||||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
|
|
||||||
public class KotlinTypedHandler extends TypedHandlerDelegate {
|
class KotlinTypedHandlerInner {
|
||||||
private final static TokenSet CONTROL_FLOW_EXPRESSIONS = TokenSet.create(
|
final static TokenSet CONTROL_FLOW_EXPRESSIONS = TokenSet.create(
|
||||||
KtNodeTypes.IF,
|
KtNodeTypes.IF,
|
||||||
KtNodeTypes.ELSE,
|
KtNodeTypes.ELSE,
|
||||||
KtNodeTypes.FOR,
|
KtNodeTypes.FOR,
|
||||||
KtNodeTypes.WHILE,
|
KtNodeTypes.WHILE,
|
||||||
KtNodeTypes.TRY);
|
KtNodeTypes.TRY);
|
||||||
|
|
||||||
private final static TokenSet SUPPRESS_AUTO_INSERT_CLOSE_BRACE_AFTER = TokenSet.create(
|
final static TokenSet SUPPRESS_AUTO_INSERT_CLOSE_BRACE_AFTER = TokenSet.create(
|
||||||
KtTokens.RPAR,
|
KtTokens.RPAR,
|
||||||
KtTokens.ELSE_KEYWORD,
|
KtTokens.ELSE_KEYWORD,
|
||||||
KtTokens.TRY_KEYWORD
|
KtTokens.TRY_KEYWORD
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class KotlinTypedHandler extends TypedHandlerDelegate {
|
||||||
private boolean kotlinLTTyped;
|
private boolean kotlinLTTyped;
|
||||||
|
|
||||||
private boolean isGlobalPreviousDollarInString; // Global flag for all editors
|
private boolean isGlobalPreviousDollarInString; // Global flag for all editors
|
||||||
@@ -107,7 +109,7 @@ public class KotlinTypedHandler extends TypedHandlerDelegate {
|
|||||||
iterator.retreat();
|
iterator.retreat();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iterator.atEnd() || !(SUPPRESS_AUTO_INSERT_CLOSE_BRACE_AFTER.contains(iterator.getTokenType()))) {
|
if (iterator.atEnd() || !(KotlinTypedHandlerInner.SUPPRESS_AUTO_INSERT_CLOSE_BRACE_AFTER.contains(iterator.getTokenType()))) {
|
||||||
AutoPopupController.getInstance(project).autoPopupParameterInfo(editor, null);
|
AutoPopupController.getInstance(project).autoPopupParameterInfo(editor, null);
|
||||||
return Result.CONTINUE;
|
return Result.CONTINUE;
|
||||||
}
|
}
|
||||||
@@ -119,7 +121,7 @@ public class KotlinTypedHandler extends TypedHandlerDelegate {
|
|||||||
PsiElement leaf = file.findElementAt(offset);
|
PsiElement leaf = file.findElementAt(offset);
|
||||||
if (leaf != null) {
|
if (leaf != null) {
|
||||||
PsiElement parent = leaf.getParent();
|
PsiElement parent = leaf.getParent();
|
||||||
if (parent != null && CONTROL_FLOW_EXPRESSIONS.contains(parent.getNode().getElementType())) {
|
if (parent != null && KotlinTypedHandlerInner.CONTROL_FLOW_EXPRESSIONS.contains(parent.getNode().getElementType())) {
|
||||||
ASTNode nonWhitespaceSibling = FormatterUtil.getPreviousNonWhitespaceSibling(leaf.getNode());
|
ASTNode nonWhitespaceSibling = FormatterUtil.getPreviousNonWhitespaceSibling(leaf.getNode());
|
||||||
if (nonWhitespaceSibling != null && nonWhitespaceSibling.getStartOffset() == tokenBeforeBraceOffset) {
|
if (nonWhitespaceSibling != null && nonWhitespaceSibling.getStartOffset() == tokenBeforeBraceOffset) {
|
||||||
EditorModificationUtil.insertStringAtCaret(editor, "{", false, true);
|
EditorModificationUtil.insertStringAtCaret(editor, "{", false, true);
|
||||||
|
|||||||
@@ -34,7 +34,9 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
|||||||
class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(KtForExpression::class.java, "Add indices to 'for' loop"),
|
class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(KtForExpression::class.java, "Add indices to 'for' loop"),
|
||||||
LowPriorityAction {
|
LowPriorityAction {
|
||||||
private val WITH_INDEX_NAME = "withIndex"
|
private val WITH_INDEX_NAME = "withIndex"
|
||||||
private val WITH_INDEX_FQ_NAMES = sequenceOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$WITH_INDEX_NAME" }.toSet()
|
private val WITH_INDEX_FQ_NAMES: Set<String> by lazy {
|
||||||
|
sequenceOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$WITH_INDEX_NAME" }.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
override fun applicabilityRange(element: KtForExpression): TextRange? {
|
override fun applicabilityRange(element: KtForExpression): TextRange? {
|
||||||
if (element.loopParameter == null) return null
|
if (element.loopParameter == null) return null
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ class ConvertForEachToForLoopIntention : SelfTargetingOffsetIndependentIntention
|
|||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val FOR_EACH_NAME = "forEach"
|
private const val FOR_EACH_NAME = "forEach"
|
||||||
private val FOR_EACH_FQ_NAMES = sequenceOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$FOR_EACH_NAME" }.toSet()
|
private val FOR_EACH_FQ_NAMES: Set<String> by lazy {
|
||||||
|
sequenceOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$FOR_EACH_NAME" }.toSet()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isApplicableTo(element: KtSimpleNameExpression): Boolean {
|
override fun isApplicableTo(element: KtSimpleNameExpression): Boolean {
|
||||||
|
|||||||
@@ -49,8 +49,6 @@ class LambdaToAnonymousFunctionIntention : SelfTargetingIntention<KtLambdaExpres
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val typeSourceCode = IdeDescriptorRenderers.SOURCE_CODE_TYPES
|
|
||||||
|
|
||||||
fun convertLambdaToFunction(
|
fun convertLambdaToFunction(
|
||||||
lambda: KtLambdaExpression,
|
lambda: KtLambdaExpression,
|
||||||
functionDescriptor: FunctionDescriptor,
|
functionDescriptor: FunctionDescriptor,
|
||||||
@@ -58,6 +56,7 @@ class LambdaToAnonymousFunctionIntention : SelfTargetingIntention<KtLambdaExpres
|
|||||||
typeParameters: Map<String, KtTypeReference> = emptyMap(),
|
typeParameters: Map<String, KtTypeReference> = emptyMap(),
|
||||||
replaceElement: (KtNamedFunction) -> KtExpression = { lambda.replaced(it) }
|
replaceElement: (KtNamedFunction) -> KtExpression = { lambda.replaced(it) }
|
||||||
): KtExpression? {
|
): KtExpression? {
|
||||||
|
val typeSourceCode = IdeDescriptorRenderers.SOURCE_CODE_TYPES
|
||||||
val functionLiteral = lambda.functionLiteral
|
val functionLiteral = lambda.functionLiteral
|
||||||
val bodyExpression = functionLiteral.bodyExpression ?: return null
|
val bodyExpression = functionLiteral.bodyExpression ?: return null
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ class RemoveForLoopIndicesInspection : IntentionBasedInspection<KtForExpression>
|
|||||||
|
|
||||||
class RemoveForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(KtForExpression::class.java, "Remove indices in 'for' loop") {
|
class RemoveForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(KtForExpression::class.java, "Remove indices in 'for' loop") {
|
||||||
private val WITH_INDEX_NAME = "withIndex"
|
private val WITH_INDEX_NAME = "withIndex"
|
||||||
private val WITH_INDEX_FQ_NAMES = sequenceOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$WITH_INDEX_NAME" }.toSet()
|
private val WITH_INDEX_FQ_NAMES: Set<String> by lazy {
|
||||||
|
sequenceOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$WITH_INDEX_NAME" }.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
override fun applicabilityRange(element: KtForExpression): TextRange? {
|
override fun applicabilityRange(element: KtForExpression): TextRange? {
|
||||||
val loopRange = element.loopRange as? KtDotQualifiedExpression ?: return null
|
val loopRange = element.loopRange as? KtDotQualifiedExpression ?: return null
|
||||||
|
|||||||
+12
-10
@@ -42,16 +42,18 @@ class RemoveRedundantCallsOfConversionMethodsIntention : SelfTargetingRangeInten
|
|||||||
"Remove redundant calls of the conversion method"
|
"Remove redundant calls of the conversion method"
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val targetClassMap = mapOf(
|
private val targetClassMap: Map<String, String?> by lazy {
|
||||||
"toString()" to String::class.qualifiedName,
|
mapOf(
|
||||||
"toDouble()" to Double::class.qualifiedName,
|
"toString()" to String::class.qualifiedName,
|
||||||
"toFloat()" to Float::class.qualifiedName,
|
"toDouble()" to Double::class.qualifiedName,
|
||||||
"toLong()" to Long::class.qualifiedName,
|
"toFloat()" to Float::class.qualifiedName,
|
||||||
"toInt()" to Int::class.qualifiedName,
|
"toLong()" to Long::class.qualifiedName,
|
||||||
"toChar()" to Char::class.qualifiedName,
|
"toInt()" to Int::class.qualifiedName,
|
||||||
"toShort()" to Short::class.qualifiedName,
|
"toChar()" to Char::class.qualifiedName,
|
||||||
"toByte()" to Byte::class.qualifiedName
|
"toShort()" to Short::class.qualifiedName,
|
||||||
)
|
"toByte()" to Byte::class.qualifiedName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun applyTo(element: KtQualifiedExpression, editor: Editor?) {
|
override fun applyTo(element: KtQualifiedExpression, editor: Editor?) {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class ReplaceAddWithPlusAssignIntention : SelfTargetingOffsetIndependentIntentio
|
|||||||
KtDotQualifiedExpression::class.java,
|
KtDotQualifiedExpression::class.java,
|
||||||
"Replace with '+='"
|
"Replace with '+='"
|
||||||
) {
|
) {
|
||||||
private val compatibleNames = setOf("add", "addAll")
|
private val compatibleNames: Set<String> by lazy { setOf("add", "addAll") }
|
||||||
|
|
||||||
override fun isApplicableTo(element: KtDotQualifiedExpression): Boolean {
|
override fun isApplicableTo(element: KtDotQualifiedExpression): Boolean {
|
||||||
if (element.callExpression?.valueArguments?.size != 1) return false
|
if (element.callExpression?.valueArguments?.size != 1) return false
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.intention.LowPriorityAction
|
|||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import org.jetbrains.kotlin.idea.core.copied
|
import org.jetbrains.kotlin.idea.core.copied
|
||||||
import org.jetbrains.kotlin.idea.util.PsiPrecedences
|
import org.jetbrains.kotlin.idea.util.PsiPrecedences
|
||||||
|
import org.jetbrains.kotlin.lexer.KtSingleValueToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
@@ -29,11 +30,14 @@ import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
|||||||
|
|
||||||
class SwapBinaryExpressionIntention : SelfTargetingIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Flip binary expression"), LowPriorityAction {
|
class SwapBinaryExpressionIntention : SelfTargetingIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Flip binary expression"), LowPriorityAction {
|
||||||
companion object {
|
companion object {
|
||||||
private val SUPPORTED_OPERATIONS = setOf(PLUS, MUL, OROR, ANDAND, EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ, GT, LT, GTEQ, LTEQ)
|
private val SUPPORTED_OPERATIONS: Set<KtSingleValueToken> by lazy {
|
||||||
|
setOf(PLUS, MUL, OROR, ANDAND, EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ, GT, LT, GTEQ, LTEQ)
|
||||||
|
}
|
||||||
|
|
||||||
private val SUPPORTED_OPERATION_NAMES =
|
private val SUPPORTED_OPERATION_NAMES: Set<String> by lazy {
|
||||||
SUPPORTED_OPERATIONS.asSequence().mapNotNull { OperatorConventions.BINARY_OPERATION_NAMES[it]?.asString() }.toSet() +
|
SUPPORTED_OPERATIONS.asSequence().mapNotNull { OperatorConventions.BINARY_OPERATION_NAMES[it]?.asString() }.toSet() +
|
||||||
setOf("xor", "or", "and", "equals")
|
setOf("xor", "or", "and", "equals")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean {
|
override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean {
|
||||||
|
|||||||
@@ -136,7 +136,9 @@ class KotlinReportSubmitter : ITNReporterCompat() {
|
|||||||
return ChronoUnit.DAYS.between(releaseDate, LocalDate.now()) > NUMBER_OF_REPORTING_DAYS_FROM_RELEASE
|
return ChronoUnit.DAYS.between(releaseDate, LocalDate.now()) > NUMBER_OF_REPORTING_DAYS_FROM_RELEASE
|
||||||
}
|
}
|
||||||
|
|
||||||
private val RELEASE_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd")
|
private val RELEASE_DATE_FORMATTER: DateTimeFormatter by lazy {
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd")
|
||||||
|
}
|
||||||
|
|
||||||
private fun readStoredPluginReleaseDate(): LocalDate? {
|
private fun readStoredPluginReleaseDate(): LocalDate? {
|
||||||
val pluginVersionToReleaseDate = PropertiesComponent.getInstance().getValue(KOTLIN_PLUGIN_RELEASE_DATE) ?: return null
|
val pluginVersionToReleaseDate = PropertiesComponent.getInstance().getValue(KOTLIN_PLUGIN_RELEASE_DATE) ?: return null
|
||||||
|
|||||||
@@ -46,55 +46,59 @@ object KotlinJvmMetadataVersionIndex : KotlinMetadataVersionIndexBase<KotlinJvmM
|
|||||||
|
|
||||||
private const val VERSION = 5
|
private const val VERSION = 5
|
||||||
|
|
||||||
private val kindsToIndex = setOf(
|
private val kindsToIndex: Set<KotlinClassHeader.Kind> by lazy {
|
||||||
KotlinClassHeader.Kind.CLASS,
|
setOf(
|
||||||
KotlinClassHeader.Kind.FILE_FACADE,
|
KotlinClassHeader.Kind.CLASS,
|
||||||
KotlinClassHeader.Kind.MULTIFILE_CLASS
|
KotlinClassHeader.Kind.FILE_FACADE,
|
||||||
)
|
KotlinClassHeader.Kind.MULTIFILE_CLASS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private val INDEXER = DataIndexer<JvmMetadataVersion, Void, FileContent> { inputData: FileContent ->
|
private val INDEXER: DataIndexer<JvmMetadataVersion, Void, FileContent> by lazy {
|
||||||
var versionArray: IntArray? = null
|
DataIndexer<JvmMetadataVersion, Void, FileContent> { inputData: FileContent ->
|
||||||
var isStrictSemantics = false
|
var versionArray: IntArray? = null
|
||||||
var annotationPresent = false
|
var isStrictSemantics = false
|
||||||
var kind: KotlinClassHeader.Kind? = null
|
var annotationPresent = false
|
||||||
|
var kind: KotlinClassHeader.Kind? = null
|
||||||
|
|
||||||
tryBlock(inputData) {
|
tryBlock(inputData) {
|
||||||
val classReader = ClassReader(inputData.content)
|
val classReader = ClassReader(inputData.content)
|
||||||
classReader.accept(object : ClassVisitor(Opcodes.API_VERSION) {
|
classReader.accept(object : ClassVisitor(Opcodes.API_VERSION) {
|
||||||
override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? {
|
override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? {
|
||||||
if (desc != METADATA_DESC) return null
|
if (desc != METADATA_DESC) return null
|
||||||
|
|
||||||
annotationPresent = true
|
annotationPresent = true
|
||||||
return object : AnnotationVisitor(Opcodes.API_VERSION) {
|
return object : AnnotationVisitor(Opcodes.API_VERSION) {
|
||||||
override fun visit(name: String, value: Any) {
|
override fun visit(name: String, value: Any) {
|
||||||
when (name) {
|
when (name) {
|
||||||
METADATA_VERSION_FIELD_NAME -> if (value is IntArray) {
|
METADATA_VERSION_FIELD_NAME -> if (value is IntArray) {
|
||||||
versionArray = value
|
versionArray = value
|
||||||
}
|
}
|
||||||
KIND_FIELD_NAME -> if (value is Int) {
|
KIND_FIELD_NAME -> if (value is Int) {
|
||||||
kind = KotlinClassHeader.Kind.getById(value)
|
kind = KotlinClassHeader.Kind.getById(value)
|
||||||
}
|
}
|
||||||
METADATA_EXTRA_INT_FIELD_NAME -> if (value is Int) {
|
METADATA_EXTRA_INT_FIELD_NAME -> if (value is Int) {
|
||||||
isStrictSemantics = (value and METADATA_STRICT_VERSION_SEMANTICS_FLAG) != 0
|
isStrictSemantics = (value and METADATA_STRICT_VERSION_SEMANTICS_FLAG) != 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
|
||||||
}, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
|
}
|
||||||
|
|
||||||
|
var version =
|
||||||
|
if (versionArray != null) createBinaryVersion(versionArray!!, isStrictSemantics) else null
|
||||||
|
|
||||||
|
if (kind !in kindsToIndex) {
|
||||||
|
// Do not index metadata version for synthetic classes
|
||||||
|
version = null
|
||||||
|
} else if (annotationPresent && version == null) {
|
||||||
|
// No version at all because the class is too old, or version is set to something weird
|
||||||
|
version = JvmMetadataVersion.INVALID_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version != null) mapOf(version to null) else emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
var version =
|
|
||||||
if (versionArray != null) createBinaryVersion(versionArray!!, isStrictSemantics) else null
|
|
||||||
|
|
||||||
if (kind !in kindsToIndex) {
|
|
||||||
// Do not index metadata version for synthetic classes
|
|
||||||
version = null
|
|
||||||
} else if (annotationPresent && version == null) {
|
|
||||||
// No version at all because the class is too old, or version is set to something weird
|
|
||||||
version = JvmMetadataVersion.INVALID_VERSION
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version != null) mapOf(version to null) else emptyMap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user