Faster startup avoiding unnecessary class loading

This commit is contained in:
Alexander Podkhalyuzin
2019-05-29 09:35:12 +02:00
committed by Vladimir Dolzhenko
parent f7d0be980b
commit c853ae49a2
22 changed files with 147 additions and 119 deletions
@@ -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
} }
@@ -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
} }
@@ -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
} }
} }
} }
@@ -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))
@@ -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)
@@ -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
) { ) {
@@ -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())
} }
} }
} }
@@ -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
) )
@@ -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
@@ -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()
} }
} }