Minimize changes in 202 bunch
This commit is contained in:
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.common.bridges.findImplementationFromInterfa
|
|||||||
import org.jetbrains.kotlin.backend.common.bridges.firstSuperMethodFromKotlin
|
import org.jetbrains.kotlin.backend.common.bridges.firstSuperMethodFromKotlin
|
||||||
import org.jetbrains.kotlin.codegen.context.ClassContext
|
import org.jetbrains.kotlin.codegen.context.ClassContext
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
|
import org.jetbrains.kotlin.codegen.state.JvmMethodExceptionTypes
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||||
@@ -167,7 +168,7 @@ class InterfaceImplBodyCodegen(
|
|||||||
name: String,
|
name: String,
|
||||||
desc: String,
|
desc: String,
|
||||||
signature: String?,
|
signature: String?,
|
||||||
exceptions: Array<out String>?
|
exceptions: JvmMethodExceptionTypes
|
||||||
): MethodVisitor {
|
): MethodVisitor {
|
||||||
if (shouldCount) {
|
if (shouldCount) {
|
||||||
isAnythingGenerated = true
|
isAnythingGenerated = true
|
||||||
|
|||||||
@@ -1,182 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.codegen
|
|
||||||
|
|
||||||
import com.intellij.util.ArrayUtil
|
|
||||||
import org.jetbrains.kotlin.backend.common.bridges.findImplementationFromInterface
|
|
||||||
import org.jetbrains.kotlin.backend.common.bridges.firstSuperMethodFromKotlin
|
|
||||||
import org.jetbrains.kotlin.codegen.context.ClassContext
|
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
|
||||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
|
||||||
|
|
||||||
class InterfaceImplBodyCodegen(
|
|
||||||
aClass: KtPureClassOrObject,
|
|
||||||
context: ClassContext,
|
|
||||||
v: ClassBuilder,
|
|
||||||
state: GenerationState,
|
|
||||||
parentCodegen: MemberCodegen<*>?
|
|
||||||
) : ClassBodyCodegen(aClass, context, InterfaceImplBodyCodegen.InterfaceImplClassBuilder(v), state, parentCodegen) {
|
|
||||||
private var isAnythingGenerated: Boolean = false
|
|
||||||
get() = (v as InterfaceImplClassBuilder).isAnythingGenerated
|
|
||||||
|
|
||||||
private val defaultImplType = typeMapper.mapDefaultImpls(descriptor)
|
|
||||||
|
|
||||||
override fun generateDeclaration() {
|
|
||||||
val codegenFlags = ACC_PUBLIC or ACC_FINAL or ACC_SUPER
|
|
||||||
val flags = if (state.classBuilderMode == ClassBuilderMode.LIGHT_CLASSES) codegenFlags or ACC_STATIC else codegenFlags
|
|
||||||
v.defineClass(
|
|
||||||
myClass.psiOrParent, state.classFileVersion, flags,
|
|
||||||
defaultImplType.internalName,
|
|
||||||
null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY
|
|
||||||
)
|
|
||||||
v.visitSource(myClass.containingKtFile.name, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun classForInnerClassRecord(): ClassDescriptor? {
|
|
||||||
if (!isAnythingGenerated) return null
|
|
||||||
return InnerClassConsumer.classForInnerClassRecord(descriptor, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun generateSyntheticPartsAfterBody() {
|
|
||||||
for (memberDescriptor in descriptor.defaultType.memberScope.getContributedDescriptors()) {
|
|
||||||
if (memberDescriptor !is CallableMemberDescriptor) continue
|
|
||||||
|
|
||||||
if (memberDescriptor.kind.isReal) continue
|
|
||||||
if (memberDescriptor.visibility == Visibilities.INVISIBLE_FAKE) continue
|
|
||||||
if (memberDescriptor.modality == Modality.ABSTRACT) continue
|
|
||||||
|
|
||||||
val implementation = findImplementationFromInterface(memberDescriptor) ?: continue
|
|
||||||
|
|
||||||
// If implementation is a default interface method (JVM 8 only)
|
|
||||||
if (implementation.isDefinitelyNotDefaultImplsMethod()) continue
|
|
||||||
|
|
||||||
if (memberDescriptor is FunctionDescriptor) {
|
|
||||||
generateDelegationToSuperDefaultImpls(memberDescriptor, implementation as FunctionDescriptor)
|
|
||||||
}
|
|
||||||
else if (memberDescriptor is PropertyDescriptor) {
|
|
||||||
implementation as PropertyDescriptor
|
|
||||||
val getter = memberDescriptor.getter
|
|
||||||
val implGetter = implementation.getter
|
|
||||||
if (getter != null && implGetter != null) {
|
|
||||||
generateDelegationToSuperDefaultImpls(getter, implGetter)
|
|
||||||
}
|
|
||||||
val setter = memberDescriptor.setter
|
|
||||||
val implSetter = implementation.setter
|
|
||||||
if (setter != null && implSetter != null) {
|
|
||||||
generateDelegationToSuperDefaultImpls(setter, implSetter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
generateSyntheticAccessors()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun generateDelegationToSuperDefaultImpls(descriptor: FunctionDescriptor, implementation: FunctionDescriptor) {
|
|
||||||
val delegateTo = firstSuperMethodFromKotlin(descriptor, implementation) as FunctionDescriptor? ?: return
|
|
||||||
|
|
||||||
// We can't call super methods from Java 1.8 interfaces because that requires INVOKESPECIAL which is forbidden from TImpl class
|
|
||||||
if (delegateTo is JavaMethodDescriptor) return
|
|
||||||
|
|
||||||
functionCodegen.generateMethod(
|
|
||||||
JvmDeclarationOrigin(
|
|
||||||
JvmDeclarationOriginKind.DEFAULT_IMPL_DELEGATION_TO_SUPERINTERFACE_DEFAULT_IMPL,
|
|
||||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor
|
|
||||||
),
|
|
||||||
descriptor,
|
|
||||||
object : FunctionGenerationStrategy.CodegenBased(state) {
|
|
||||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
|
||||||
val iv = codegen.v
|
|
||||||
|
|
||||||
val method = typeMapper.mapToCallableMethod(delegateTo, true)
|
|
||||||
val myParameters = signature.valueParameters
|
|
||||||
val calleeParameters = method.getValueParameters()
|
|
||||||
|
|
||||||
if (myParameters.size != calleeParameters.size) {
|
|
||||||
throw AssertionError(
|
|
||||||
"Method from super interface has a different signature.\n" +
|
|
||||||
"This method:\n%s\n%s\n%s\nSuper method:\n%s\n%s\n%s".format(
|
|
||||||
descriptor, signature, myParameters, delegateTo, method, calleeParameters
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
var k = 0
|
|
||||||
val it = calleeParameters.iterator()
|
|
||||||
for (parameter in myParameters) {
|
|
||||||
val type = parameter.asmType
|
|
||||||
StackValue.local(k, type).put(it.next().asmType, iv)
|
|
||||||
k += type.size
|
|
||||||
}
|
|
||||||
|
|
||||||
method.genInvokeInstruction(iv)
|
|
||||||
StackValue.coerce(method.returnType, signature.returnType, iv)
|
|
||||||
iv.areturn(signature.returnType)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun generateKotlinMetadataAnnotation() {
|
|
||||||
(v as InterfaceImplClassBuilder).stopCounting()
|
|
||||||
|
|
||||||
writeSyntheticClassMetadata(v, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun done() {
|
|
||||||
super.done()
|
|
||||||
if (!isAnythingGenerated) {
|
|
||||||
state.factory.removeClasses(setOf(defaultImplType.internalName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class InterfaceImplClassBuilder(private val v: ClassBuilder) : DelegatingClassBuilder() {
|
|
||||||
private var shouldCount: Boolean = true
|
|
||||||
var isAnythingGenerated: Boolean = false
|
|
||||||
private set
|
|
||||||
|
|
||||||
fun stopCounting() {
|
|
||||||
shouldCount = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getDelegate() = v
|
|
||||||
|
|
||||||
override fun newMethod(
|
|
||||||
origin: JvmDeclarationOrigin,
|
|
||||||
access: Int,
|
|
||||||
name: String,
|
|
||||||
desc: String,
|
|
||||||
signature: String?,
|
|
||||||
exceptions: Array<out String?>?
|
|
||||||
): MethodVisitor {
|
|
||||||
if (shouldCount) {
|
|
||||||
isAnythingGenerated = true
|
|
||||||
}
|
|
||||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun generateSyntheticPartsBeforeBody() {
|
|
||||||
generatePropertyMetadataArrayFieldIfNeeded(defaultImplType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-1
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen
|
package org.jetbrains.kotlin.codegen
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.state.JvmMethodExceptionTypes
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
@@ -42,7 +43,7 @@ class OriginCollectingClassBuilderFactory(private val builderMode: ClassBuilderM
|
|||||||
name: String,
|
name: String,
|
||||||
desc: String,
|
desc: String,
|
||||||
signature: String?,
|
signature: String?,
|
||||||
exceptions: Array<out String>?
|
exceptions: JvmMethodExceptionTypes
|
||||||
): MethodVisitor {
|
): MethodVisitor {
|
||||||
val methodNode = super.newMethod(origin, access, name, desc, signature, exceptions) as MethodNode
|
val methodNode = super.newMethod(origin, access, name, desc, signature, exceptions) as MethodNode
|
||||||
origins[methodNode] = origin
|
origins[methodNode] = origin
|
||||||
|
|||||||
-68
@@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.codegen
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
|
||||||
|
|
||||||
class OriginCollectingClassBuilderFactory(private val builderMode: ClassBuilderMode) : ClassBuilderFactory {
|
|
||||||
val compiledClasses = mutableListOf<ClassNode>()
|
|
||||||
val origins = mutableMapOf<Any, JvmDeclarationOrigin>()
|
|
||||||
|
|
||||||
override fun getClassBuilderMode(): ClassBuilderMode = builderMode
|
|
||||||
|
|
||||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): AbstractClassBuilder.Concrete {
|
|
||||||
val classNode = ClassNode()
|
|
||||||
compiledClasses += classNode
|
|
||||||
origins[classNode] = origin
|
|
||||||
return OriginCollectingClassBuilder(classNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class OriginCollectingClassBuilder(val classNode: ClassNode) : AbstractClassBuilder.Concrete(classNode) {
|
|
||||||
override fun newField(
|
|
||||||
origin: JvmDeclarationOrigin,
|
|
||||||
access: Int,
|
|
||||||
name: String,
|
|
||||||
desc: String,
|
|
||||||
signature: String?,
|
|
||||||
value: Any?
|
|
||||||
): FieldVisitor {
|
|
||||||
val fieldNode = super.newField(origin, access, name, desc, signature, value) as FieldNode
|
|
||||||
origins[fieldNode] = origin
|
|
||||||
return fieldNode
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newMethod(
|
|
||||||
origin: JvmDeclarationOrigin,
|
|
||||||
access: Int,
|
|
||||||
name: String,
|
|
||||||
desc: String,
|
|
||||||
signature: String?,
|
|
||||||
exceptions: Array<out String?>?
|
|
||||||
): MethodVisitor {
|
|
||||||
val methodNode = super.newMethod(origin, access, name, desc, signature, exceptions) as MethodNode
|
|
||||||
origins[methodNode] = origin
|
|
||||||
|
|
||||||
// ASM doesn't read information about local variables for the `abstract` methods so we need to get it manually
|
|
||||||
if ((access and Opcodes.ACC_ABSTRACT) != 0 && methodNode.localVariables == null) {
|
|
||||||
methodNode.localVariables = mutableListOf<LocalVariableNode>()
|
|
||||||
}
|
|
||||||
|
|
||||||
return methodNode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun asBytes(builder: ClassBuilder): ByteArray {
|
|
||||||
val classWriter = ClassWriter(0)
|
|
||||||
(builder as OriginCollectingClassBuilder).classNode.accept(classWriter)
|
|
||||||
return classWriter.toByteArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun asText(builder: ClassBuilder) = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun close() {}
|
|
||||||
}
|
|
||||||
+2
-1
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.util.containers.LinkedMultiMap
|
import com.intellij.util.containers.LinkedMultiMap
|
||||||
import com.intellij.util.containers.MultiMap
|
import com.intellij.util.containers.MultiMap
|
||||||
|
import org.jetbrains.kotlin.codegen.state.JvmMethodExceptionTypes
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ConflictingJvmDeclarationsData
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ConflictingJvmDeclarationsData
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.MemberKind
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.MemberKind
|
||||||
@@ -63,7 +64,7 @@ abstract class SignatureCollectingClassBuilderFactory(
|
|||||||
return super.newField(origin, access, name, desc, signature, value)
|
return super.newField(origin, access, name, desc, signature, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun newMethod(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor {
|
override fun newMethod(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, exceptions: JvmMethodExceptionTypes): MethodVisitor {
|
||||||
signatures.putValue(RawSignature(name, desc, MemberKind.METHOD), origin)
|
signatures.putValue(RawSignature(name, desc, MemberKind.METHOD), origin)
|
||||||
if (!shouldGenerate(origin)) {
|
if (!shouldGenerate(origin)) {
|
||||||
return AbstractClassBuilder.EMPTY_METHOD_VISITOR
|
return AbstractClassBuilder.EMPTY_METHOD_VISITOR
|
||||||
|
|||||||
-89
@@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.codegen
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.util.containers.LinkedMultiMap
|
|
||||||
import com.intellij.util.containers.MultiMap
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ConflictingJvmDeclarationsData
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.MemberKind
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.RawSignature
|
|
||||||
import org.jetbrains.org.objectweb.asm.FieldVisitor
|
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
|
||||||
|
|
||||||
abstract class SignatureCollectingClassBuilderFactory(
|
|
||||||
delegate: ClassBuilderFactory, val shouldGenerate: (JvmDeclarationOrigin) -> Boolean
|
|
||||||
) : DelegatingClassBuilderFactory(delegate) {
|
|
||||||
|
|
||||||
protected abstract fun handleClashingSignatures(data: ConflictingJvmDeclarationsData)
|
|
||||||
protected abstract fun onClassDone(classOrigin: JvmDeclarationOrigin,
|
|
||||||
classInternalName: String,
|
|
||||||
signatures: MultiMap<RawSignature, JvmDeclarationOrigin>)
|
|
||||||
|
|
||||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): DelegatingClassBuilder {
|
|
||||||
return SignatureCollectingClassBuilder(origin, delegate.newClassBuilder(origin))
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class SignatureCollectingClassBuilder(
|
|
||||||
private val classCreatedFor: JvmDeclarationOrigin,
|
|
||||||
internal val _delegate: ClassBuilder
|
|
||||||
) : DelegatingClassBuilder() {
|
|
||||||
|
|
||||||
override fun getDelegate() = _delegate
|
|
||||||
|
|
||||||
private lateinit var classInternalName: String
|
|
||||||
|
|
||||||
private val signatures = LinkedMultiMap<RawSignature, JvmDeclarationOrigin>()
|
|
||||||
|
|
||||||
override fun defineClass(origin: PsiElement?, version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<out String>) {
|
|
||||||
classInternalName = name
|
|
||||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newField(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor {
|
|
||||||
signatures.putValue(RawSignature(name, desc, MemberKind.FIELD), origin)
|
|
||||||
if (!shouldGenerate(origin)) {
|
|
||||||
return AbstractClassBuilder.EMPTY_FIELD_VISITOR
|
|
||||||
}
|
|
||||||
return super.newField(origin, access, name, desc, signature, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newMethod(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String?>?): MethodVisitor {
|
|
||||||
signatures.putValue(RawSignature(name, desc, MemberKind.METHOD), origin)
|
|
||||||
if (!shouldGenerate(origin)) {
|
|
||||||
return AbstractClassBuilder.EMPTY_METHOD_VISITOR
|
|
||||||
}
|
|
||||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun done() {
|
|
||||||
for ((signature, elementsAndDescriptors) in signatures.entrySet()) {
|
|
||||||
if (elementsAndDescriptors.size == 1) continue // no clash
|
|
||||||
handleClashingSignatures(ConflictingJvmDeclarationsData(
|
|
||||||
classInternalName,
|
|
||||||
classCreatedFor,
|
|
||||||
signature,
|
|
||||||
elementsAndDescriptors
|
|
||||||
))
|
|
||||||
}
|
|
||||||
onClassDone(classCreatedFor, classInternalName, signatures)
|
|
||||||
super.done()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-1
@@ -905,7 +905,7 @@ private class MethodNodeExaminer(
|
|||||||
val methodNode: MethodNode,
|
val methodNode: MethodNode,
|
||||||
disableTailCallOptimizationForFunctionReturningUnit: Boolean
|
disableTailCallOptimizationForFunctionReturningUnit: Boolean
|
||||||
) {
|
) {
|
||||||
private val sourceFrames: Array<Frame<SourceValue>?> =
|
private val sourceFrames: SourceFrames =
|
||||||
MethodTransformer.analyze(containingClassInternalName, methodNode, IgnoringCopyOperationSourceInterpreter())
|
MethodTransformer.analyze(containingClassInternalName, methodNode, IgnoringCopyOperationSourceInterpreter())
|
||||||
private val controlFlowGraph = ControlFlowGraph.build(methodNode)
|
private val controlFlowGraph = ControlFlowGraph.build(methodNode)
|
||||||
|
|
||||||
|
|||||||
-1236
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen.coroutines
|
||||||
|
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
|
||||||
|
|
||||||
|
typealias SourceFrames = Array<Frame<SourceValue>?>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen.coroutines
|
||||||
|
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
|
||||||
|
|
||||||
|
typealias SourceFrames = Array<Frame<SourceValue>>
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen.optimization.common
|
||||||
|
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||||
|
|
||||||
|
typealias TypeAnnotatedFrames = Array<Frame<BasicValue>?>
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen.optimization.common
|
||||||
|
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||||
|
|
||||||
|
typealias TypeAnnotatedFrames = Array<Frame<BasicValue>>
|
||||||
+1
-1
@@ -60,7 +60,7 @@ fun analyzeLiveness(node: MethodNode): List<VariableLivenessFrame> {
|
|||||||
|
|
||||||
private fun analyzeVisibleByDebuggerVariables(
|
private fun analyzeVisibleByDebuggerVariables(
|
||||||
node: MethodNode,
|
node: MethodNode,
|
||||||
typeAnnotatedFrames: Array<Frame<BasicValue>?>
|
typeAnnotatedFrames: TypeAnnotatedFrames
|
||||||
): Array<BitSet> {
|
): Array<BitSet> {
|
||||||
val res = Array(node.instructions.size()) { BitSet(node.maxLocals) }
|
val res = Array(node.instructions.size()) { BitSet(node.maxLocals) }
|
||||||
for (local in node.localVariables) {
|
for (local in node.localVariables) {
|
||||||
|
|||||||
-101
@@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
|
||||||
* that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.optimization.common
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.IincInsnNode
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
class VariableLivenessFrame(val maxLocals: Int) : VarFrame<VariableLivenessFrame> {
|
|
||||||
private val bitSet = BitSet(maxLocals)
|
|
||||||
|
|
||||||
override fun mergeFrom(other: VariableLivenessFrame) {
|
|
||||||
bitSet.or(other.bitSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun markAlive(varIndex: Int) {
|
|
||||||
bitSet.set(varIndex, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun markAllAlive(bitSet: BitSet) {
|
|
||||||
this.bitSet.or(bitSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun markDead(varIndex: Int) {
|
|
||||||
bitSet.set(varIndex, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isAlive(varIndex: Int): Boolean = bitSet.get(varIndex)
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (other !is VariableLivenessFrame) return false
|
|
||||||
return bitSet == other.bitSet
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode() = bitSet.hashCode()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun analyzeLiveness(node: MethodNode): List<VariableLivenessFrame> {
|
|
||||||
val typeAnnotatedFrames = MethodTransformer.analyze("fake", node, OptimizationBasicInterpreter())
|
|
||||||
val visibleByDebuggerVariables = analyzeVisibleByDebuggerVariables(node, typeAnnotatedFrames)
|
|
||||||
return analyze(node, object : BackwardAnalysisInterpreter<VariableLivenessFrame> {
|
|
||||||
override fun newFrame(maxLocals: Int) = VariableLivenessFrame(maxLocals)
|
|
||||||
override fun def(frame: VariableLivenessFrame, insn: AbstractInsnNode) = defVar(frame, insn)
|
|
||||||
override fun use(frame: VariableLivenessFrame, insn: AbstractInsnNode) =
|
|
||||||
useVar(frame, insn, node, visibleByDebuggerVariables[node.instructions.indexOf(insn)])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun analyzeVisibleByDebuggerVariables(
|
|
||||||
node: MethodNode,
|
|
||||||
typeAnnotatedFrames: Array<Frame<BasicValue>>
|
|
||||||
): Array<BitSet> {
|
|
||||||
val res = Array(node.instructions.size()) { BitSet(node.maxLocals) }
|
|
||||||
for (local in node.localVariables) {
|
|
||||||
if (local.name.isInvisibleDebuggerVariable()) continue
|
|
||||||
for (index in node.instructions.indexOf(local.start) until node.instructions.indexOf(local.end)) {
|
|
||||||
if (Type.getType(local.desc).sort == typeAnnotatedFrames[index]?.getLocal(local.index)?.type?.sort) {
|
|
||||||
res[index].set(local.index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun defVar(frame: VariableLivenessFrame, insn: AbstractInsnNode) {
|
|
||||||
if (insn is VarInsnNode && insn.isStoreOperation()) {
|
|
||||||
frame.markDead(insn.`var`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun useVar(
|
|
||||||
frame: VariableLivenessFrame,
|
|
||||||
insn: AbstractInsnNode,
|
|
||||||
node: MethodNode,
|
|
||||||
visibleByDebuggerVariables: BitSet
|
|
||||||
) {
|
|
||||||
frame.markAllAlive(visibleByDebuggerVariables)
|
|
||||||
|
|
||||||
if (insn is VarInsnNode && insn.isLoadOperation()) {
|
|
||||||
frame.markAlive(insn.`var`)
|
|
||||||
} else if (insn is IincInsnNode) {
|
|
||||||
frame.markAlive(insn.`var`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.isInvisibleDebuggerVariable(): Boolean =
|
|
||||||
startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT) ||
|
|
||||||
startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) ||
|
|
||||||
this == SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen.state
|
||||||
|
|
||||||
|
typealias JvmMethodExceptionTypes = Array<out String>?
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen.state
|
||||||
|
|
||||||
|
typealias JvmMethodExceptionTypes = Array<out String?>?
|
||||||
+1
-1
@@ -83,7 +83,7 @@ class SignatureDumpingBuilderFactory(
|
|||||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun newMethod(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor {
|
override fun newMethod(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, exceptions: JvmMethodExceptionTypes): MethodVisitor {
|
||||||
signatures += RawSignature(name, desc, MemberKind.METHOD) to origin.descriptor?.let {
|
signatures += RawSignature(name, desc, MemberKind.METHOD) to origin.descriptor?.let {
|
||||||
if (it is CallableDescriptor) it.unwrapInitialDescriptorForSuspendFunction() else it
|
if (it is CallableDescriptor) it.unwrapInitialDescriptorForSuspendFunction() else it
|
||||||
}
|
}
|
||||||
|
|||||||
-151
@@ -1,151 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.state
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
|
||||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
|
||||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilder
|
|
||||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilderFactory
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.MemberKind
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.RawSignature
|
|
||||||
import org.jetbrains.org.objectweb.asm.FieldVisitor
|
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
|
||||||
import java.io.BufferedWriter
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
|
|
||||||
class SignatureDumpingBuilderFactory(
|
|
||||||
builderFactory: ClassBuilderFactory,
|
|
||||||
val destination: File
|
|
||||||
) : DelegatingClassBuilderFactory(builderFactory) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val MEMBER_RENDERER = DescriptorRenderer.withOptions {
|
|
||||||
withDefinedIn = false
|
|
||||||
modifiers -= DescriptorRendererModifier.VISIBILITY
|
|
||||||
}
|
|
||||||
val TYPE_RENDERER = DescriptorRenderer.withOptions {
|
|
||||||
withSourceFileForTopLevel = false
|
|
||||||
modifiers -= DescriptorRendererModifier.VISIBILITY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val outputStream: BufferedWriter by lazy {
|
|
||||||
// TODO: Replace with LOG.info and make log output go to MessageCollector
|
|
||||||
println("[INFO] Dumping signatures to $destination")
|
|
||||||
destination.parentFile?.mkdirs()
|
|
||||||
destination.bufferedWriter().apply { append("[\n") }
|
|
||||||
}
|
|
||||||
private var firstClassWritten: Boolean = false
|
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
outputStream.append("\n]\n")
|
|
||||||
outputStream.close()
|
|
||||||
super.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): DelegatingClassBuilder {
|
|
||||||
return SignatureDumpingClassBuilder(origin, delegate.newClassBuilder(origin))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private inner class SignatureDumpingClassBuilder(val origin: JvmDeclarationOrigin, val _delegate: ClassBuilder) : DelegatingClassBuilder() {
|
|
||||||
override fun getDelegate() = _delegate
|
|
||||||
|
|
||||||
private val signatures = mutableListOf<Pair<RawSignature, DeclarationDescriptor?>>()
|
|
||||||
private lateinit var javaClassName: String
|
|
||||||
|
|
||||||
override fun defineClass(origin: PsiElement?, version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<out String>) {
|
|
||||||
javaClassName = name
|
|
||||||
|
|
||||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newMethod(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String?>?): MethodVisitor {
|
|
||||||
signatures += RawSignature(name, desc, MemberKind.METHOD) to origin.descriptor?.let {
|
|
||||||
if (it is CallableDescriptor) it.unwrapInitialDescriptorForSuspendFunction() else it
|
|
||||||
}
|
|
||||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newField(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor {
|
|
||||||
signatures += RawSignature(name, desc, MemberKind.FIELD) to origin.descriptor
|
|
||||||
return super.newField(origin, access, name, desc, signature, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun done() {
|
|
||||||
if (firstClassWritten) outputStream.append(",\n") else firstClassWritten = true
|
|
||||||
outputStream.append("\t{\n")
|
|
||||||
origin.descriptor?.let {
|
|
||||||
outputStream.append("\t\t").appendNameValue("declaration", TYPE_RENDERER.render(it)).append(",\n")
|
|
||||||
(it as? DeclarationDescriptorWithVisibility)?.visibility?.let {
|
|
||||||
outputStream.append("\t\t").appendNameValue("visibility", it.internalDisplayName).append(",\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outputStream.append("\t\t").appendNameValue("class", javaClassName).append(",\n")
|
|
||||||
|
|
||||||
outputStream.append("\t\t").appendQuoted("members").append(": [\n")
|
|
||||||
signatures.joinTo(outputStream, ",\n") { buildString {
|
|
||||||
val (signature, descriptor) = it
|
|
||||||
append("\t\t\t{")
|
|
||||||
descriptor?.let {
|
|
||||||
(it as? DeclarationDescriptorWithVisibility)?.visibility?.let {
|
|
||||||
appendNameValue("visibility", it.internalDisplayName).append(",\t")
|
|
||||||
}
|
|
||||||
appendNameValue("declaration", MEMBER_RENDERER.render(it)).append(", ")
|
|
||||||
|
|
||||||
}
|
|
||||||
appendNameValue("name", signature.name).append(", ")
|
|
||||||
appendNameValue("desc", signature.desc).append("}")
|
|
||||||
}}
|
|
||||||
outputStream.append("\n\t\t]\n\t}")
|
|
||||||
|
|
||||||
super.done()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Appendable.appendQuoted(value: String?): Appendable = value?.let { append('"').append(jsonEscape(it)).append('"') } ?: append("null")
|
|
||||||
private fun Appendable.appendNameValue(name: String, value: String?): Appendable = appendQuoted(name).append(": ").appendQuoted(value)
|
|
||||||
|
|
||||||
private fun jsonEscape(value: String): String = buildString {
|
|
||||||
for (index in 0..value.length - 1) {
|
|
||||||
val ch = value[index]
|
|
||||||
when (ch) {
|
|
||||||
'\b' -> append("\\b")
|
|
||||||
'\t' -> append("\\t")
|
|
||||||
'\n' -> append("\\n")
|
|
||||||
'\r' -> append("\\r")
|
|
||||||
'\"' -> append("\\\"")
|
|
||||||
'\\' -> append("\\\\")
|
|
||||||
else -> if (ch.toInt() < 32) {
|
|
||||||
append("\\u" + Integer.toHexString(ch.toInt()).padStart(4, '0'))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
append(ch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-1
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.highlighter.markers.LineMarkerInfos
|
||||||
import org.jetbrains.kotlin.idea.inspections.RecursivePropertyAccessorInspection
|
import org.jetbrains.kotlin.idea.inspections.RecursivePropertyAccessorInspection
|
||||||
import org.jetbrains.kotlin.idea.util.getReceiverTargetDescriptor
|
import org.jetbrains.kotlin.idea.util.getReceiverTargetDescriptor
|
||||||
import org.jetbrains.kotlin.lexer.KtToken
|
import org.jetbrains.kotlin.lexer.KtToken
|
||||||
@@ -45,7 +46,7 @@ import java.util.*
|
|||||||
class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
|
class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
|
||||||
override fun getLineMarkerInfo(element: PsiElement) = null
|
override fun getLineMarkerInfo(element: PsiElement) = null
|
||||||
|
|
||||||
override fun collectSlowLineMarkers(elements: MutableList<PsiElement>, result: MutableCollection<LineMarkerInfo<*>>) {
|
override fun collectSlowLineMarkers(elements: MutableList<PsiElement>, result: LineMarkerInfos) {
|
||||||
val markedLineNumbers = HashSet<Int>()
|
val markedLineNumbers = HashSet<Int>()
|
||||||
|
|
||||||
for (element in elements) {
|
for (element in elements) {
|
||||||
|
|||||||
+2
-1
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.highlighter.markers.LineMarkerInfos
|
||||||
import org.jetbrains.kotlin.idea.inspections.RecursivePropertyAccessorInspection
|
import org.jetbrains.kotlin.idea.inspections.RecursivePropertyAccessorInspection
|
||||||
import org.jetbrains.kotlin.idea.util.getReceiverTargetDescriptor
|
import org.jetbrains.kotlin.idea.util.getReceiverTargetDescriptor
|
||||||
import org.jetbrains.kotlin.lexer.KtToken
|
import org.jetbrains.kotlin.lexer.KtToken
|
||||||
@@ -45,7 +46,7 @@ import java.util.*
|
|||||||
class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
|
class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
|
||||||
override fun getLineMarkerInfo(element: PsiElement) = null
|
override fun getLineMarkerInfo(element: PsiElement) = null
|
||||||
|
|
||||||
override fun collectSlowLineMarkers(elements: MutableList<out PsiElement>, result: MutableCollection<in LineMarkerInfo<*>>) {
|
override fun collectSlowLineMarkers(elements: MutableList<out PsiElement>, result: LineMarkerInfos) {
|
||||||
val markedLineNumbers = HashSet<Int>()
|
val markedLineNumbers = HashSet<Int>()
|
||||||
|
|
||||||
for (element in elements) {
|
for (element in elements) {
|
||||||
|
|||||||
+2
-1
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.descriptors.accessors
|
|||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.highlighter.markers.LineMarkerInfos
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
|
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -48,7 +49,7 @@ class KotlinSuspendCallLineMarkerProvider : LineMarkerProvider {
|
|||||||
|
|
||||||
override fun collectSlowLineMarkers(
|
override fun collectSlowLineMarkers(
|
||||||
elements: MutableList<PsiElement>,
|
elements: MutableList<PsiElement>,
|
||||||
result: MutableCollection<LineMarkerInfo<*>>
|
result: LineMarkerInfos
|
||||||
) {
|
) {
|
||||||
val markedLineNumbers = HashSet<Int>()
|
val markedLineNumbers = HashSet<Int>()
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.descriptors.accessors
|
|||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.highlighter.markers.LineMarkerInfos
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
|
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -48,7 +49,7 @@ class KotlinSuspendCallLineMarkerProvider : LineMarkerProvider {
|
|||||||
|
|
||||||
override fun collectSlowLineMarkers(
|
override fun collectSlowLineMarkers(
|
||||||
elements: MutableList<out PsiElement>,
|
elements: MutableList<out PsiElement>,
|
||||||
result: MutableCollection<in LineMarkerInfo<*>>
|
result: LineMarkerInfos
|
||||||
) {
|
) {
|
||||||
val markedLineNumbers = HashSet<Int>()
|
val markedLineNumbers = HashSet<Int>()
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ private val toolTipHandler = Function<PsiElement, String> {
|
|||||||
|
|
||||||
fun collectHighlightingColorsMarkers(
|
fun collectHighlightingColorsMarkers(
|
||||||
ktClass: KtClass,
|
ktClass: KtClass,
|
||||||
result: MutableCollection<LineMarkerInfo<*>>
|
result: LineMarkerInfos
|
||||||
) {
|
) {
|
||||||
if (!KotlinLineMarkerOptions.dslOption.isEnabled) return
|
if (!KotlinLineMarkerOptions.dslOption.isEnabled) return
|
||||||
|
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.highlighter.markers
|
|
||||||
|
|
||||||
import com.intellij.application.options.colors.ColorAndFontOptions
|
|
||||||
import com.intellij.codeHighlighting.Pass
|
|
||||||
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler
|
|
||||||
import com.intellij.codeInsight.daemon.LineMarkerInfo
|
|
||||||
import com.intellij.ide.DataManager
|
|
||||||
import com.intellij.openapi.editor.markup.GutterIconRenderer
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.util.Function
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
|
||||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
|
||||||
import org.jetbrains.kotlin.idea.highlighter.dsl.DslHighlighterExtension
|
|
||||||
import org.jetbrains.kotlin.idea.highlighter.dsl.isDslHighlightingMarker
|
|
||||||
import org.jetbrains.kotlin.psi.KtClass
|
|
||||||
import javax.swing.JComponent
|
|
||||||
|
|
||||||
private val navHandler = GutterIconNavigationHandler<PsiElement> { event, element ->
|
|
||||||
val dataContext = (event.component as? JComponent)?.let { DataManager.getInstance().getDataContext(it) }
|
|
||||||
?: return@GutterIconNavigationHandler
|
|
||||||
val ktClass = element?.parent as? KtClass ?: return@GutterIconNavigationHandler
|
|
||||||
val styleId = ktClass.styleIdForMarkerAnnotation() ?: return@GutterIconNavigationHandler
|
|
||||||
ColorAndFontOptions.selectOrEditColor(dataContext, DslHighlighterExtension.styleOptionDisplayName(styleId), KotlinLanguage.NAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val toolTipHandler = Function<PsiElement, String> {
|
|
||||||
KotlinBundle.message("highlighter.tool.tip.marker.annotation.for.dsl")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun collectHighlightingColorsMarkers(
|
|
||||||
ktClass: KtClass,
|
|
||||||
result: MutableCollection<in LineMarkerInfo<*>>
|
|
||||||
) {
|
|
||||||
if (!KotlinLineMarkerOptions.dslOption.isEnabled) return
|
|
||||||
|
|
||||||
val styleId = ktClass.styleIdForMarkerAnnotation() ?: return
|
|
||||||
|
|
||||||
val anchor = ktClass.nameIdentifier ?: return
|
|
||||||
|
|
||||||
result.add(
|
|
||||||
LineMarkerInfo<PsiElement>(
|
|
||||||
anchor,
|
|
||||||
anchor.textRange,
|
|
||||||
createDslStyleIcon(styleId),
|
|
||||||
Pass.LINE_MARKERS,
|
|
||||||
toolTipHandler, navHandler,
|
|
||||||
GutterIconRenderer.Alignment.RIGHT
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtClass.styleIdForMarkerAnnotation(): Int? {
|
|
||||||
val classDescriptor = toDescriptor() as? ClassDescriptor ?: return null
|
|
||||||
if (classDescriptor.kind != ClassKind.ANNOTATION_CLASS) return null
|
|
||||||
if (!classDescriptor.isDslHighlightingMarker()) return null
|
|
||||||
return DslHighlighterExtension.styleIdByMarkerAnnotation(classDescriptor)
|
|
||||||
}
|
|
||||||
@@ -83,7 +83,7 @@ class KotlinLineMarkerProvider : LineMarkerProviderDescriptor() {
|
|||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun collectSlowLineMarkers(elements: List<PsiElement>, result: MutableCollection<LineMarkerInfo<*>>) {
|
override fun collectSlowLineMarkers(elements: List<PsiElement>, result: LineMarkerInfos) {
|
||||||
if (elements.isEmpty()) return
|
if (elements.isEmpty()) return
|
||||||
if (KotlinLineMarkerOptions.options.none { option -> option.isEnabled }) return
|
if (KotlinLineMarkerOptions.options.none { option -> option.isEnabled }) return
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ private fun isImplementsAndNotOverrides(
|
|||||||
return descriptor.modality != Modality.ABSTRACT && overriddenMembers.all { it.modality == Modality.ABSTRACT }
|
return descriptor.modality != Modality.ABSTRACT && overriddenMembers.all { it.modality == Modality.ABSTRACT }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectSuperDeclarationMarkers(declaration: KtDeclaration, result: MutableCollection<LineMarkerInfo<*>>) {
|
private fun collectSuperDeclarationMarkers(declaration: KtDeclaration, result: LineMarkerInfos) {
|
||||||
if (!(KotlinLineMarkerOptions.implementingOption.isEnabled || KotlinLineMarkerOptions.overridingOption.isEnabled)) return
|
if (!(KotlinLineMarkerOptions.implementingOption.isEnabled || KotlinLineMarkerOptions.overridingOption.isEnabled)) return
|
||||||
|
|
||||||
assert(declaration is KtNamedFunction || declaration is KtProperty || declaration is KtParameter)
|
assert(declaration is KtNamedFunction || declaration is KtProperty || declaration is KtParameter)
|
||||||
@@ -287,7 +287,7 @@ private fun collectSuperDeclarationMarkers(declaration: KtDeclaration, result: M
|
|||||||
result.add(lineMarkerInfo)
|
result.add(lineMarkerInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectInheritedClassMarker(element: KtClass, result: MutableCollection<LineMarkerInfo<*>>) {
|
private fun collectInheritedClassMarker(element: KtClass, result: LineMarkerInfos) {
|
||||||
if (!(KotlinLineMarkerOptions.implementedOption.isEnabled || KotlinLineMarkerOptions.overriddenOption.isEnabled)) return
|
if (!(KotlinLineMarkerOptions.implementedOption.isEnabled || KotlinLineMarkerOptions.overriddenOption.isEnabled)) return
|
||||||
|
|
||||||
if (!element.isInheritable()) {
|
if (!element.isInheritable()) {
|
||||||
@@ -321,7 +321,7 @@ private fun collectInheritedClassMarker(element: KtClass, result: MutableCollect
|
|||||||
|
|
||||||
private fun collectOverriddenPropertyAccessors(
|
private fun collectOverriddenPropertyAccessors(
|
||||||
properties: Collection<KtNamedDeclaration>,
|
properties: Collection<KtNamedDeclaration>,
|
||||||
result: MutableCollection<LineMarkerInfo<*>>
|
result: LineMarkerInfos
|
||||||
) {
|
) {
|
||||||
if (!(KotlinLineMarkerOptions.implementedOption.isEnabled || KotlinLineMarkerOptions.overriddenOption.isEnabled)) return
|
if (!(KotlinLineMarkerOptions.implementedOption.isEnabled || KotlinLineMarkerOptions.overriddenOption.isEnabled)) return
|
||||||
|
|
||||||
@@ -368,7 +368,7 @@ private val KtNamedDeclaration.expectOrActualAnchor
|
|||||||
|
|
||||||
private fun collectMultiplatformMarkers(
|
private fun collectMultiplatformMarkers(
|
||||||
declaration: KtNamedDeclaration,
|
declaration: KtNamedDeclaration,
|
||||||
result: MutableCollection<LineMarkerInfo<*>>
|
result: LineMarkerInfos
|
||||||
) {
|
) {
|
||||||
if (KotlinLineMarkerOptions.actualOption.isEnabled) {
|
if (KotlinLineMarkerOptions.actualOption.isEnabled) {
|
||||||
if (declaration.isExpectDeclaration()) {
|
if (declaration.isExpectDeclaration()) {
|
||||||
@@ -460,7 +460,7 @@ internal fun KtDeclaration.findMarkerBoundDeclarations(): Sequence<KtNamedDeclar
|
|||||||
|
|
||||||
private fun collectActualMarkers(
|
private fun collectActualMarkers(
|
||||||
declaration: KtNamedDeclaration,
|
declaration: KtNamedDeclaration,
|
||||||
result: MutableCollection<LineMarkerInfo<*>>
|
result: LineMarkerInfos
|
||||||
) {
|
) {
|
||||||
if (!KotlinLineMarkerOptions.actualOption.isEnabled) return
|
if (!KotlinLineMarkerOptions.actualOption.isEnabled) return
|
||||||
if (declaration.requiresNoMarkers()) return
|
if (declaration.requiresNoMarkers()) return
|
||||||
@@ -491,7 +491,7 @@ private fun collectActualMarkers(
|
|||||||
|
|
||||||
private fun collectExpectedMarkers(
|
private fun collectExpectedMarkers(
|
||||||
declaration: KtNamedDeclaration,
|
declaration: KtNamedDeclaration,
|
||||||
result: MutableCollection<LineMarkerInfo<*>>
|
result: LineMarkerInfos
|
||||||
) {
|
) {
|
||||||
if (!KotlinLineMarkerOptions.expectOption.isEnabled) return
|
if (!KotlinLineMarkerOptions.expectOption.isEnabled) return
|
||||||
|
|
||||||
@@ -520,7 +520,7 @@ private fun collectExpectedMarkers(
|
|||||||
result.add(lineMarkerInfo)
|
result.add(lineMarkerInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectOverriddenFunctions(functions: Collection<KtNamedFunction>, result: MutableCollection<LineMarkerInfo<*>>) {
|
private fun collectOverriddenFunctions(functions: Collection<KtNamedFunction>, result: LineMarkerInfos) {
|
||||||
if (!(KotlinLineMarkerOptions.implementedOption.isEnabled || KotlinLineMarkerOptions.overriddenOption.isEnabled)) {
|
if (!(KotlinLineMarkerOptions.implementedOption.isEnabled || KotlinLineMarkerOptions.overriddenOption.isEnabled)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
-561
@@ -1,561 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.highlighter.markers
|
|
||||||
|
|
||||||
import com.intellij.codeHighlighting.Pass
|
|
||||||
import com.intellij.codeInsight.daemon.*
|
|
||||||
import com.intellij.codeInsight.daemon.impl.LineMarkerNavigator
|
|
||||||
import com.intellij.codeInsight.daemon.impl.MarkerType
|
|
||||||
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator
|
|
||||||
import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask
|
|
||||||
import com.intellij.openapi.actionSystem.IdeActions
|
|
||||||
import com.intellij.openapi.editor.Document
|
|
||||||
import com.intellij.openapi.editor.colors.CodeInsightColors
|
|
||||||
import com.intellij.openapi.editor.colors.EditorColorsManager
|
|
||||||
import com.intellij.openapi.editor.markup.GutterIconRenderer
|
|
||||||
import com.intellij.openapi.editor.markup.SeparatorPlacement
|
|
||||||
import com.intellij.openapi.progress.ProgressManager
|
|
||||||
import com.intellij.openapi.project.DumbService
|
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
|
||||||
import com.intellij.psi.*
|
|
||||||
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
|
||||||
import org.jetbrains.kotlin.asJava.toLightClass
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightClass
|
|
||||||
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightMethod
|
|
||||||
import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors
|
|
||||||
import org.jetbrains.kotlin.idea.caches.project.implementingDescriptors
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.core.isInheritable
|
|
||||||
import org.jetbrains.kotlin.idea.core.isOverridable
|
|
||||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.editor.fixers.startLine
|
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
|
||||||
import org.jetbrains.kotlin.idea.presentation.DeclarationByModuleRenderer
|
|
||||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.toPossiblyFakeLightMethods
|
|
||||||
import org.jetbrains.kotlin.idea.util.*
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespaceAndComments
|
|
||||||
import java.awt.event.MouseEvent
|
|
||||||
import java.util.*
|
|
||||||
import javax.swing.ListCellRenderer
|
|
||||||
|
|
||||||
class KotlinLineMarkerProvider : LineMarkerProviderDescriptor() {
|
|
||||||
override fun getName() = KotlinBundle.message("highlighter.name.kotlin.line.markers")
|
|
||||||
|
|
||||||
override fun getOptions(): Array<Option> = KotlinLineMarkerOptions.options
|
|
||||||
|
|
||||||
override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<PsiElement>? {
|
|
||||||
if (DaemonCodeAnalyzerSettings.getInstance().SHOW_METHOD_SEPARATORS) {
|
|
||||||
if (element.canHaveSeparator()) {
|
|
||||||
val prevSibling = element.getPrevSiblingIgnoringWhitespaceAndComments()
|
|
||||||
if (prevSibling.canHaveSeparator() &&
|
|
||||||
(element.wantsSeparator() || prevSibling?.wantsSeparator() == true)
|
|
||||||
) {
|
|
||||||
return createLineSeparatorByElement(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PsiElement?.canHaveSeparator() =
|
|
||||||
this is KtFunction || this is KtClassInitializer || (this is KtProperty && !isLocal)
|
|
||||||
|
|
||||||
private fun PsiElement.wantsSeparator() = this is KtFunction || StringUtil.getLineBreakCount(text) > 0
|
|
||||||
|
|
||||||
private fun createLineSeparatorByElement(element: PsiElement): LineMarkerInfo<PsiElement> {
|
|
||||||
val anchor = PsiTreeUtil.getDeepestFirst(element)
|
|
||||||
|
|
||||||
val info = LineMarkerInfo(anchor, anchor.textRange, null, Pass.LINE_MARKERS, null, null, GutterIconRenderer.Alignment.RIGHT)
|
|
||||||
info.separatorColor = EditorColorsManager.getInstance().globalScheme.getColor(CodeInsightColors.METHOD_SEPARATORS_COLOR)
|
|
||||||
info.separatorPlacement = SeparatorPlacement.TOP
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun collectSlowLineMarkers(elements: List<PsiElement>, result: MutableCollection<in LineMarkerInfo<*>>) {
|
|
||||||
if (elements.isEmpty()) return
|
|
||||||
if (KotlinLineMarkerOptions.options.none { option -> option.isEnabled }) return
|
|
||||||
|
|
||||||
val first = elements.first()
|
|
||||||
if (DumbService.getInstance(first.project).isDumb || !ProjectRootsUtil.isInProjectOrLibSource(first)) return
|
|
||||||
|
|
||||||
val functions = hashSetOf<KtNamedFunction>()
|
|
||||||
val properties = hashSetOf<KtNamedDeclaration>()
|
|
||||||
val declarations = hashSetOf<KtNamedDeclaration>()
|
|
||||||
|
|
||||||
for (leaf in elements) {
|
|
||||||
ProgressManager.checkCanceled()
|
|
||||||
if (leaf !is PsiIdentifier && leaf.firstChild != null) continue
|
|
||||||
val element = leaf.parent as? KtNamedDeclaration ?: continue
|
|
||||||
if (!declarations.add(element)) continue
|
|
||||||
|
|
||||||
when (element) {
|
|
||||||
is KtClass -> {
|
|
||||||
collectInheritedClassMarker(element, result)
|
|
||||||
collectHighlightingColorsMarkers(element, result)
|
|
||||||
}
|
|
||||||
is KtNamedFunction -> {
|
|
||||||
functions.add(element)
|
|
||||||
collectSuperDeclarationMarkers(element, result)
|
|
||||||
}
|
|
||||||
is KtProperty -> {
|
|
||||||
properties.add(element)
|
|
||||||
collectSuperDeclarationMarkers(element, result)
|
|
||||||
}
|
|
||||||
is KtParameter -> {
|
|
||||||
if (element.hasValOrVar()) {
|
|
||||||
properties.add(element)
|
|
||||||
collectSuperDeclarationMarkers(element, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
collectMultiplatformMarkers(element, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
collectOverriddenFunctions(functions, result)
|
|
||||||
collectOverriddenPropertyAccessors(properties, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class NavigationPopupDescriptor(
|
|
||||||
val targets: Collection<NavigatablePsiElement>,
|
|
||||||
val title: String,
|
|
||||||
val findUsagesTitle: String,
|
|
||||||
val renderer: ListCellRenderer<*>,
|
|
||||||
val updater: ListBackgroundUpdaterTask? = null
|
|
||||||
) {
|
|
||||||
fun showPopup(e: MouseEvent?) {
|
|
||||||
PsiElementListNavigator.openTargets(e, targets.toTypedArray(), title, findUsagesTitle, renderer, updater)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TestableLineMarkerNavigator {
|
|
||||||
fun getTargetsPopupDescriptor(element: PsiElement?): NavigationPopupDescriptor?
|
|
||||||
}
|
|
||||||
|
|
||||||
private val SUBCLASSED_CLASS = MarkerType(
|
|
||||||
"SUBCLASSED_CLASS",
|
|
||||||
{ getPsiClass(it)?.let(::getSubclassedClassTooltip) },
|
|
||||||
object : LineMarkerNavigator() {
|
|
||||||
override fun browse(e: MouseEvent?, element: PsiElement?) {
|
|
||||||
getPsiClass(element)?.let {
|
|
||||||
MarkerType.navigateToSubclassedClass(e, it, DeclarationByModuleRenderer())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
private val OVERRIDDEN_FUNCTION = object : MarkerType(
|
|
||||||
"OVERRIDDEN_FUNCTION",
|
|
||||||
{ getPsiMethod(it)?.let(::getOverriddenMethodTooltip) },
|
|
||||||
object : LineMarkerNavigator() {
|
|
||||||
override fun browse(e: MouseEvent?, element: PsiElement?) {
|
|
||||||
buildNavigateToOverriddenMethodPopup(e, element)?.showPopup(e)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
|
|
||||||
override fun getNavigationHandler(): GutterIconNavigationHandler<PsiElement> {
|
|
||||||
val superHandler = super.getNavigationHandler()
|
|
||||||
return object : GutterIconNavigationHandler<PsiElement>, TestableLineMarkerNavigator {
|
|
||||||
override fun navigate(e: MouseEvent?, elt: PsiElement?) {
|
|
||||||
superHandler.navigate(e, elt)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getTargetsPopupDescriptor(element: PsiElement?) = buildNavigateToOverriddenMethodPopup(null, element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val OVERRIDDEN_PROPERTY = object : MarkerType(
|
|
||||||
"OVERRIDDEN_PROPERTY",
|
|
||||||
{ it?.let { getOverriddenPropertyTooltip(it.parent as KtNamedDeclaration) } },
|
|
||||||
object : LineMarkerNavigator() {
|
|
||||||
override fun browse(e: MouseEvent?, element: PsiElement?) {
|
|
||||||
buildNavigateToPropertyOverriddenDeclarationsPopup(e, element)?.showPopup(e)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
|
|
||||||
override fun getNavigationHandler(): GutterIconNavigationHandler<PsiElement> {
|
|
||||||
val superHandler = super.getNavigationHandler()
|
|
||||||
return object : GutterIconNavigationHandler<PsiElement>, TestableLineMarkerNavigator {
|
|
||||||
override fun navigate(e: MouseEvent?, elt: PsiElement?) {
|
|
||||||
superHandler.navigate(e, elt)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getTargetsPopupDescriptor(element: PsiElement?) = buildNavigateToPropertyOverriddenDeclarationsPopup(null, element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val PsiElement.markerDeclaration
|
|
||||||
get() = (this as? KtDeclaration) ?: (parent as? KtDeclaration)
|
|
||||||
|
|
||||||
private val PLATFORM_ACTUAL = object : MarkerType(
|
|
||||||
"PLATFORM_ACTUAL",
|
|
||||||
{ element -> element?.markerDeclaration?.let { getPlatformActualTooltip(it) } },
|
|
||||||
object : LineMarkerNavigator() {
|
|
||||||
override fun browse(e: MouseEvent?, element: PsiElement?) {
|
|
||||||
buildNavigateToActualDeclarationsPopup(element)?.showPopup(e)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
override fun getNavigationHandler(): GutterIconNavigationHandler<PsiElement> {
|
|
||||||
val superHandler = super.getNavigationHandler()
|
|
||||||
return object : GutterIconNavigationHandler<PsiElement>, TestableLineMarkerNavigator {
|
|
||||||
override fun navigate(e: MouseEvent?, elt: PsiElement?) {
|
|
||||||
superHandler.navigate(e, elt)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getTargetsPopupDescriptor(element: PsiElement?): NavigationPopupDescriptor? {
|
|
||||||
return buildNavigateToActualDeclarationsPopup(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val EXPECTED_DECLARATION = object : MarkerType(
|
|
||||||
"EXPECTED_DECLARATION",
|
|
||||||
{ element -> element?.markerDeclaration?.let { getExpectedDeclarationTooltip(it) } },
|
|
||||||
object : LineMarkerNavigator() {
|
|
||||||
override fun browse(e: MouseEvent?, element: PsiElement?) {
|
|
||||||
buildNavigateToExpectedDeclarationsPopup(element)?.showPopup(e)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
override fun getNavigationHandler(): GutterIconNavigationHandler<PsiElement> {
|
|
||||||
val superHandler = super.getNavigationHandler()
|
|
||||||
return object : GutterIconNavigationHandler<PsiElement>, TestableLineMarkerNavigator {
|
|
||||||
override fun navigate(e: MouseEvent?, elt: PsiElement?) {
|
|
||||||
superHandler.navigate(e, elt)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getTargetsPopupDescriptor(element: PsiElement?): NavigationPopupDescriptor? {
|
|
||||||
return buildNavigateToExpectedDeclarationsPopup(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isImplementsAndNotOverrides(
|
|
||||||
descriptor: CallableMemberDescriptor,
|
|
||||||
overriddenMembers: Collection<CallableMemberDescriptor>
|
|
||||||
): Boolean {
|
|
||||||
return descriptor.modality != Modality.ABSTRACT && overriddenMembers.all { it.modality == Modality.ABSTRACT }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectSuperDeclarationMarkers(declaration: KtDeclaration, result: MutableCollection<in LineMarkerInfo<*>>) {
|
|
||||||
if (!(KotlinLineMarkerOptions.implementingOption.isEnabled || KotlinLineMarkerOptions.overridingOption.isEnabled)) return
|
|
||||||
|
|
||||||
assert(declaration is KtNamedFunction || declaration is KtProperty || declaration is KtParameter)
|
|
||||||
|
|
||||||
if (!declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return
|
|
||||||
|
|
||||||
val resolveWithParents = resolveDeclarationWithParents(declaration)
|
|
||||||
if (resolveWithParents.overriddenDescriptors.isEmpty()) return
|
|
||||||
|
|
||||||
val implements = isImplementsAndNotOverrides(resolveWithParents.descriptor!!, resolveWithParents.overriddenDescriptors)
|
|
||||||
|
|
||||||
val anchor = (declaration as? KtNamedDeclaration)?.nameIdentifier ?: declaration
|
|
||||||
|
|
||||||
// NOTE: Don't store descriptors in line markers because line markers are not deleted while editing other files and this can prevent
|
|
||||||
// clearing the whole BindingTrace.
|
|
||||||
|
|
||||||
val lineMarkerInfo = LineMarkerInfo(
|
|
||||||
anchor,
|
|
||||||
anchor.textRange,
|
|
||||||
if (implements) KotlinLineMarkerOptions.implementingOption.icon else KotlinLineMarkerOptions.overridingOption.icon,
|
|
||||||
Pass.LINE_MARKERS,
|
|
||||||
SuperDeclarationMarkerTooltip,
|
|
||||||
SuperDeclarationMarkerNavigationHandler(),
|
|
||||||
GutterIconRenderer.Alignment.RIGHT
|
|
||||||
)
|
|
||||||
NavigateAction.setNavigateAction(
|
|
||||||
lineMarkerInfo,
|
|
||||||
if (declaration is KtNamedFunction) KotlinBundle.message("highlighter.action.text.go.to.super.method") else KotlinBundle.message(
|
|
||||||
"highlighter.action.text.go.to.super.property"
|
|
||||||
),
|
|
||||||
IdeActions.ACTION_GOTO_SUPER
|
|
||||||
)
|
|
||||||
result.add(lineMarkerInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectInheritedClassMarker(element: KtClass, result: MutableCollection<in LineMarkerInfo<*>>) {
|
|
||||||
if (!(KotlinLineMarkerOptions.implementedOption.isEnabled || KotlinLineMarkerOptions.overriddenOption.isEnabled)) return
|
|
||||||
|
|
||||||
if (!element.isInheritable()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val lightClass = element.toLightClass() ?: KtFakeLightClass(element)
|
|
||||||
|
|
||||||
if (ClassInheritorsSearch.search(lightClass, false).findFirst() == null) return
|
|
||||||
|
|
||||||
val anchor = element.nameIdentifier ?: element
|
|
||||||
|
|
||||||
val lineMarkerInfo = LineMarkerInfo(
|
|
||||||
anchor,
|
|
||||||
anchor.textRange,
|
|
||||||
if (element.isInterface()) KotlinLineMarkerOptions.implementedOption.icon else KotlinLineMarkerOptions.overriddenOption.icon,
|
|
||||||
Pass.LINE_MARKERS,
|
|
||||||
SUBCLASSED_CLASS.tooltip,
|
|
||||||
SUBCLASSED_CLASS.navigationHandler,
|
|
||||||
GutterIconRenderer.Alignment.RIGHT
|
|
||||||
)
|
|
||||||
NavigateAction.setNavigateAction(
|
|
||||||
lineMarkerInfo,
|
|
||||||
if (element.isInterface()) KotlinBundle.message("highlighter.action.text.go.to.implementations") else KotlinBundle.message(
|
|
||||||
"highlighter.action.text.go.to.subclasses"
|
|
||||||
),
|
|
||||||
IdeActions.ACTION_GOTO_IMPLEMENTATION
|
|
||||||
)
|
|
||||||
result.add(lineMarkerInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectOverriddenPropertyAccessors(
|
|
||||||
properties: Collection<KtNamedDeclaration>,
|
|
||||||
result: MutableCollection<in LineMarkerInfo<*>>
|
|
||||||
) {
|
|
||||||
if (!(KotlinLineMarkerOptions.implementedOption.isEnabled || KotlinLineMarkerOptions.overriddenOption.isEnabled)) return
|
|
||||||
|
|
||||||
val mappingToJava = HashMap<PsiElement, KtNamedDeclaration>()
|
|
||||||
for (property in properties) {
|
|
||||||
if (property.isOverridable()) {
|
|
||||||
property.toPossiblyFakeLightMethods().forEach { mappingToJava[it] = property }
|
|
||||||
mappingToJava[property] = property
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val classes = collectContainingClasses(mappingToJava.keys.filterIsInstance<PsiMethod>())
|
|
||||||
|
|
||||||
for (property in getOverriddenDeclarations(mappingToJava, classes)) {
|
|
||||||
ProgressManager.checkCanceled()
|
|
||||||
|
|
||||||
val anchor = (property as? PsiNameIdentifierOwner)?.nameIdentifier ?: property
|
|
||||||
|
|
||||||
val lineMarkerInfo = LineMarkerInfo(
|
|
||||||
anchor,
|
|
||||||
anchor.textRange,
|
|
||||||
if (isImplemented(property)) KotlinLineMarkerOptions.implementedOption.icon else KotlinLineMarkerOptions.overriddenOption.icon,
|
|
||||||
Pass.LINE_MARKERS,
|
|
||||||
OVERRIDDEN_PROPERTY.tooltip,
|
|
||||||
OVERRIDDEN_PROPERTY.navigationHandler,
|
|
||||||
GutterIconRenderer.Alignment.RIGHT
|
|
||||||
)
|
|
||||||
NavigateAction.setNavigateAction(
|
|
||||||
lineMarkerInfo,
|
|
||||||
KotlinBundle.message("highlighter.action.text.go.to.overridden.properties"),
|
|
||||||
IdeActions.ACTION_GOTO_IMPLEMENTATION
|
|
||||||
)
|
|
||||||
result.add(lineMarkerInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val KtNamedDeclaration.expectOrActualAnchor
|
|
||||||
get() =
|
|
||||||
nameIdentifier ?: when (this) {
|
|
||||||
is KtConstructor<*> -> getConstructorKeyword() ?: getValueParameterList()?.leftParenthesis
|
|
||||||
is KtObjectDeclaration -> getObjectKeyword()
|
|
||||||
else -> null
|
|
||||||
} ?: this
|
|
||||||
|
|
||||||
private fun collectMultiplatformMarkers(
|
|
||||||
declaration: KtNamedDeclaration,
|
|
||||||
result: MutableCollection<in LineMarkerInfo<*>>
|
|
||||||
) {
|
|
||||||
if (KotlinLineMarkerOptions.actualOption.isEnabled) {
|
|
||||||
if (declaration.isExpectDeclaration()) {
|
|
||||||
collectActualMarkers(declaration, result)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KotlinLineMarkerOptions.expectOption.isEnabled) {
|
|
||||||
if (!declaration.isExpectDeclaration() && declaration.isEffectivelyActual()) {
|
|
||||||
collectExpectedMarkers(declaration, result)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Document.areAnchorsOnOneLine(
|
|
||||||
first: KtNamedDeclaration,
|
|
||||||
second: KtNamedDeclaration?
|
|
||||||
): Boolean {
|
|
||||||
if (second == null) return false
|
|
||||||
val firstAnchor = first.expectOrActualAnchor
|
|
||||||
val secondAnchor = second.expectOrActualAnchor
|
|
||||||
return firstAnchor.startLine(this) == secondAnchor.startLine(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtNamedDeclaration.requiresNoMarkers(
|
|
||||||
document: Document? = PsiDocumentManager.getInstance(project).getDocument(containingFile)
|
|
||||||
): Boolean {
|
|
||||||
when (this) {
|
|
||||||
is KtPrimaryConstructor -> {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
is KtParameter,
|
|
||||||
is KtEnumEntry -> {
|
|
||||||
if (document?.areAnchorsOnOneLine(this, containingClassOrObject) == true) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (this is KtEnumEntry) {
|
|
||||||
val enumEntries = containingClassOrObject?.body?.enumEntries.orEmpty()
|
|
||||||
val previousEnumEntry = enumEntries.getOrNull(enumEntries.indexOf(this) - 1)
|
|
||||||
if (document?.areAnchorsOnOneLine(this, previousEnumEntry) == true) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this is KtParameter && hasValOrVar()) {
|
|
||||||
val parameters = containingClassOrObject?.primaryConstructorParameters.orEmpty()
|
|
||||||
val previousParameter = parameters.getOrNull(parameters.indexOf(this) - 1)
|
|
||||||
if (document?.areAnchorsOnOneLine(this, previousParameter) == true) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun KtDeclaration.findMarkerBoundDeclarations(): Sequence<KtNamedDeclaration> {
|
|
||||||
if (this !is KtClass && this !is KtParameter) return emptySequence()
|
|
||||||
val document = PsiDocumentManager.getInstance(project).getDocument(containingFile)
|
|
||||||
|
|
||||||
fun <T : KtNamedDeclaration> Sequence<T>.takeBound(bound: KtNamedDeclaration) = takeWhile {
|
|
||||||
document?.areAnchorsOnOneLine(bound, it) == true
|
|
||||||
}
|
|
||||||
|
|
||||||
return when (this) {
|
|
||||||
is KtParameter -> {
|
|
||||||
val propertyParameters = takeIf { hasValOrVar() }?.containingClassOrObject?.primaryConstructorParameters
|
|
||||||
?: return emptySequence()
|
|
||||||
propertyParameters.asSequence().dropWhile {
|
|
||||||
it !== this
|
|
||||||
}.drop(1).takeBound(this).filter { it.hasValOrVar() }
|
|
||||||
}
|
|
||||||
is KtEnumEntry -> {
|
|
||||||
val enumEntries = containingClassOrObject?.body?.enumEntries ?: return emptySequence()
|
|
||||||
enumEntries.asSequence().dropWhile {
|
|
||||||
it !== this
|
|
||||||
}.drop(1).takeBound(this)
|
|
||||||
}
|
|
||||||
is KtClass -> {
|
|
||||||
val boundParameters =
|
|
||||||
primaryConstructor?.valueParameters?.asSequence()?.takeBound(this)?.filter { it.hasValOrVar() }.orEmpty()
|
|
||||||
val boundEnumEntries = this.takeIf { isEnum() }?.body?.enumEntries?.asSequence()?.takeBound(this).orEmpty()
|
|
||||||
boundParameters + boundEnumEntries
|
|
||||||
}
|
|
||||||
else -> emptySequence()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectActualMarkers(
|
|
||||||
declaration: KtNamedDeclaration,
|
|
||||||
result: MutableCollection<in LineMarkerInfo<*>>
|
|
||||||
) {
|
|
||||||
if (!KotlinLineMarkerOptions.actualOption.isEnabled) return
|
|
||||||
if (declaration.requiresNoMarkers()) return
|
|
||||||
|
|
||||||
val descriptor = declaration.toDescriptor() as? MemberDescriptor ?: return
|
|
||||||
val commonModuleDescriptor = declaration.containingKtFile.findModuleDescriptor()
|
|
||||||
|
|
||||||
if (commonModuleDescriptor.implementingDescriptors.none { it.hasActualsFor(descriptor) }) return
|
|
||||||
|
|
||||||
val anchor = declaration.expectOrActualAnchor
|
|
||||||
|
|
||||||
val lineMarkerInfo = LineMarkerInfo(
|
|
||||||
anchor,
|
|
||||||
anchor.textRange,
|
|
||||||
KotlinLineMarkerOptions.actualOption.icon,
|
|
||||||
Pass.LINE_MARKERS,
|
|
||||||
PLATFORM_ACTUAL.tooltip,
|
|
||||||
PLATFORM_ACTUAL.navigationHandler,
|
|
||||||
GutterIconRenderer.Alignment.RIGHT
|
|
||||||
)
|
|
||||||
NavigateAction.setNavigateAction(
|
|
||||||
lineMarkerInfo,
|
|
||||||
KotlinBundle.message("highlighter.action.text.go.to.actual.declarations"),
|
|
||||||
IdeActions.ACTION_GOTO_IMPLEMENTATION
|
|
||||||
)
|
|
||||||
result.add(lineMarkerInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectExpectedMarkers(
|
|
||||||
declaration: KtNamedDeclaration,
|
|
||||||
result: MutableCollection<in LineMarkerInfo<*>>
|
|
||||||
) {
|
|
||||||
if (!KotlinLineMarkerOptions.expectOption.isEnabled) return
|
|
||||||
|
|
||||||
if (declaration.requiresNoMarkers()) return
|
|
||||||
|
|
||||||
val descriptor = declaration.toDescriptor() as? MemberDescriptor ?: return
|
|
||||||
val platformModuleDescriptor = declaration.containingKtFile.findModuleDescriptor()
|
|
||||||
if (!platformModuleDescriptor.implementedDescriptors.any { it.hasDeclarationOf(descriptor) }) return
|
|
||||||
|
|
||||||
val anchor = declaration.expectOrActualAnchor
|
|
||||||
|
|
||||||
val lineMarkerInfo = LineMarkerInfo(
|
|
||||||
anchor,
|
|
||||||
anchor.textRange,
|
|
||||||
KotlinLineMarkerOptions.expectOption.icon,
|
|
||||||
Pass.LINE_MARKERS,
|
|
||||||
EXPECTED_DECLARATION.tooltip,
|
|
||||||
EXPECTED_DECLARATION.navigationHandler,
|
|
||||||
GutterIconRenderer.Alignment.RIGHT
|
|
||||||
)
|
|
||||||
NavigateAction.setNavigateAction(
|
|
||||||
lineMarkerInfo,
|
|
||||||
KotlinBundle.message("highlighter.action.text.go.to.expected.declaration"),
|
|
||||||
null
|
|
||||||
)
|
|
||||||
result.add(lineMarkerInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectOverriddenFunctions(functions: Collection<KtNamedFunction>, result: MutableCollection<in LineMarkerInfo<*>>) {
|
|
||||||
if (!(KotlinLineMarkerOptions.implementedOption.isEnabled || KotlinLineMarkerOptions.overriddenOption.isEnabled)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val mappingToJava = HashMap<PsiElement, KtNamedFunction>()
|
|
||||||
for (function in functions) {
|
|
||||||
if (function.isOverridable()) {
|
|
||||||
val method = LightClassUtil.getLightClassMethod(function) ?: KtFakeLightMethod.get(function)
|
|
||||||
if (method != null) {
|
|
||||||
mappingToJava[method] = function
|
|
||||||
}
|
|
||||||
mappingToJava[function] = function
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val classes = collectContainingClasses(mappingToJava.keys.filterIsInstance<PsiMethod>())
|
|
||||||
|
|
||||||
for (function in getOverriddenDeclarations(mappingToJava, classes)) {
|
|
||||||
ProgressManager.checkCanceled()
|
|
||||||
|
|
||||||
val anchor = function.nameIdentifier ?: function
|
|
||||||
|
|
||||||
val lineMarkerInfo = LineMarkerInfo(
|
|
||||||
anchor,
|
|
||||||
anchor.textRange,
|
|
||||||
if (isImplemented(function)) KotlinLineMarkerOptions.implementedOption.icon else KotlinLineMarkerOptions.overriddenOption.icon,
|
|
||||||
Pass.LINE_MARKERS, OVERRIDDEN_FUNCTION.tooltip,
|
|
||||||
OVERRIDDEN_FUNCTION.navigationHandler,
|
|
||||||
GutterIconRenderer.Alignment.RIGHT
|
|
||||||
)
|
|
||||||
NavigateAction.setNavigateAction(
|
|
||||||
lineMarkerInfo,
|
|
||||||
KotlinBundle.message("highlighter.action.text.go.to.overridden.methods"),
|
|
||||||
IdeActions.ACTION_GOTO_IMPLEMENTATION
|
|
||||||
)
|
|
||||||
result.add(lineMarkerInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.highlighter.markers
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.LineMarkerInfo
|
||||||
|
|
||||||
|
typealias LineMarkerInfos = MutableCollection<LineMarkerInfo<*>>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.highlighter.markers
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.LineMarkerInfo
|
||||||
|
|
||||||
|
typealias LineMarkerInfos = MutableCollection<in LineMarkerInfo<*>>
|
||||||
Reference in New Issue
Block a user