show line markers for properties defined in the primary constructor (KT-12626)

This commit is contained in:
Dmitry Jemerov
2016-07-14 15:49:26 +02:00
parent 4391d833b9
commit e224041760
7 changed files with 85 additions and 36 deletions
@@ -180,8 +180,11 @@ fun KtDeclaration.isOverridable(): Boolean {
val parent = parent
if (!(parent is KtClassBody || parent is KtParameterList)) return false
val klass = parent.parent as? KtClass ?: return false
if (!klass.isInheritable() && !klass.isEnum()) return false
val klass = if (parent.parent is KtPrimaryConstructor)
parent.parent.parent as? KtClass
else
parent.parent as? KtClass
if (klass == null || (!klass.isInheritable() && !klass.isEnum())) return false
if (hasModifier(KtTokens.FINAL_KEYWORD) || hasModifier(KtTokens.PRIVATE_KEYWORD)) return false
@@ -27,6 +27,7 @@ import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.DumbService
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.search.searches.ClassInheritorsSearch
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.toLightClass
@@ -34,10 +35,7 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isOverridable
import java.awt.event.MouseEvent
import java.util.*
@@ -56,7 +54,7 @@ class KotlinLineMarkerProvider : LineMarkerProvider {
if (DumbService.getInstance(first.project).isDumb || !ProjectRootsUtil.isInProjectOrLibSource(first)) return
val functions = HashSet<KtNamedFunction>()
val properties = HashSet<KtProperty>()
val properties = HashSet<KtNamedDeclaration>()
for (element in elements) {
ProgressManager.checkCanceled()
@@ -73,6 +71,12 @@ class KotlinLineMarkerProvider : LineMarkerProvider {
properties.add(element)
collectSuperDeclarationMarkers(element, result)
}
is KtParameter -> {
if (element.hasValOrVar()) {
properties.add(element)
collectSuperDeclarationMarkers(element, result)
}
}
}
}
@@ -103,7 +107,7 @@ private val OVERRIDDEN_FUNCTION = MarkerType(
})
private val OVERRIDDEN_PROPERTY = MarkerType(
{ it?.let { getOverriddenPropertyTooltip(it.parent as KtProperty) } },
{ it?.let { getOverriddenPropertyTooltip(it.parent as KtNamedDeclaration) } },
object : LineMarkerNavigator() {
override fun browse(e: MouseEvent?, element: PsiElement?) {
element?.let { navigateToPropertyOverriddenDeclarations(e, it.parent as KtProperty) }
@@ -115,7 +119,7 @@ private fun isImplementsAndNotOverrides(descriptor: CallableMemberDescriptor, ov
}
private fun collectSuperDeclarationMarkers(declaration: KtDeclaration, result: MutableCollection<LineMarkerInfo<*>>) {
assert(declaration is KtNamedFunction || declaration is KtProperty)
assert(declaration is KtNamedFunction || declaration is KtProperty || declaration is KtParameter)
if (!declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return
@@ -160,11 +164,13 @@ private fun collectInheritedClassMarker(element: KtClass, result: MutableCollect
))
}
private fun collectOverriddenPropertyAccessors(properties: Collection<KtProperty>, result: MutableCollection<LineMarkerInfo<*>>) {
val mappingToJava = HashMap<PsiMethod, KtProperty>()
private fun collectOverriddenPropertyAccessors(properties: Collection<KtNamedDeclaration>,
result: MutableCollection<LineMarkerInfo<*>>) {
val mappingToJava = HashMap<PsiMethod, KtNamedDeclaration>()
for (property in properties) {
if (property.isOverridable()) {
val accessorsPsiMethods = LightClassUtil.getLightClassPropertyMethods(property)
val accessorsPsiMethods = property.getAccessorLightMethods()
for (psiMethod in accessorsPsiMethods) {
mappingToJava.put(psiMethod, property)
}
@@ -176,7 +182,7 @@ private fun collectOverriddenPropertyAccessors(properties: Collection<KtProperty
for (property in getOverriddenDeclarations(mappingToJava, classes)) {
ProgressManager.checkCanceled()
val anchor = property.nameIdentifier ?: property
val anchor = (property as? PsiNameIdentifierOwner)?.nameIdentifier ?: property
result.add(LineMarkerInfo(
anchor,
@@ -190,6 +196,14 @@ private fun collectOverriddenPropertyAccessors(properties: Collection<KtProperty
}
}
fun KtNamedDeclaration.getAccessorLightMethods(): LightClassUtil.PropertyAccessorsPsiMethods {
return when (this) {
is KtProperty -> LightClassUtil.getLightClassPropertyMethods(this)
is KtParameter -> LightClassUtil.getLightClassPropertyMethods(this)
else -> throw IllegalStateException("Unexpected property type: ${this}")
}
}
private fun collectOverriddenFunctions(functions: Collection<KtNamedFunction>, result: MutableCollection<LineMarkerInfo<*>>) {
val mappingToJava = HashMap<PsiMethod, KtNamedFunction>()
for (function in functions) {
@@ -16,33 +16,33 @@
package org.jetbrains.kotlin.idea.highlighter.markers
import com.intellij.psi.search.PsiElementProcessor
import com.intellij.psi.PsiClass
import org.jetbrains.kotlin.idea.KotlinBundle
import com.intellij.psi.search.searches.OverridingMethodsSearch
import org.jetbrains.kotlin.asJava.LightClassUtil
import com.intellij.psi.PsiMethod
import com.intellij.util.AdapterProcessor
import com.intellij.util.CommonProcessors
import com.intellij.psi.search.PsiElementProcessorAdapter
import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper
import com.intellij.psi.PsiElement
import java.awt.event.MouseEvent
import com.intellij.openapi.project.DumbService
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.openapi.progress.ProgressManager
import com.intellij.codeInsight.daemon.impl.MarkerType
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator
import com.intellij.ide.util.DefaultPsiElementCellRenderer
import com.intellij.ide.util.PsiClassListCellRenderer
import javax.swing.JComponent
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.DumbService
import com.intellij.psi.NavigatablePsiElement
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.PsiElementProcessor
import com.intellij.psi.search.PsiElementProcessorAdapter
import com.intellij.psi.search.searches.OverridingMethodsSearch
import com.intellij.util.AdapterProcessor
import com.intellij.util.CommonProcessors
import com.intellij.util.Function
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import java.awt.event.MouseEvent
import javax.swing.JComponent
fun getOverriddenPropertyTooltip(property: KtProperty): String? {
fun getOverriddenPropertyTooltip(property: KtNamedDeclaration): String? {
val overriddenInClassesProcessor = PsiElementProcessor.CollectElementsWithLimit<PsiClass>(5)
val consumer = AdapterProcessor<PsiMethod, PsiClass>(
@@ -50,7 +50,7 @@ fun getOverriddenPropertyTooltip(property: KtProperty): String? {
Function { method: PsiMethod? -> method?.containingClass }
)
for (method in LightClassUtil.getLightClassPropertyMethods(property)) {
for (method in property.getAccessorLightMethods()) {
if (!overriddenInClassesProcessor.isOverflow) {
OverridingMethodsSearch.search(method, true).forEach(consumer)
}
@@ -27,17 +27,17 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.codeInsight.KtFunctionPsiElementCellRenderer
import org.jetbrains.kotlin.idea.search.usagesSearch.propertyDescriptor
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.RenderingFormat
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.OverrideResolver
import java.awt.event.MouseEvent
import java.util.ArrayList
import java.util.*
object SuperDeclarationMarkerTooltip: Function<KtDeclaration, String> {
override fun `fun`(ktDeclaration: KtDeclaration?): String? {
@@ -112,7 +112,10 @@ data class ResolveWithParentsResult(
val overriddenDescriptors: Collection<CallableMemberDescriptor>)
fun resolveDeclarationWithParents(element: KtDeclaration): ResolveWithParentsResult {
val descriptor = element.resolveToDescriptorIfAny()
val descriptor = if (element is KtParameter)
element.propertyDescriptor
else
element.resolveToDescriptorIfAny()
if (descriptor !is CallableMemberDescriptor) return ResolveWithParentsResult(null, listOf())
@@ -0,0 +1,10 @@
open class <lineMarker></lineMarker>C(
open val <lineMarker descr="<html><body>Is overridden in <br/>&nbsp;&nbsp;&nbsp;&nbsp;D</body></html>"></lineMarker>s: String
) {
}
class D : C("") {
override val <lineMarker></lineMarker>s: String get() = "q"
}
@@ -0,0 +1,7 @@
interface <lineMarker></lineMarker>I {
val <lineMarker></lineMarker>name: String
}
class D(
override val <lineMarker descr="Implements property in 'I'"></lineMarker>name: String
): I
@@ -163,6 +163,18 @@ public class LineMarkersTestGenerated extends AbstractLineMarkersTest {
doTest(fileName);
}
@TestMetadata("PrimaryConstructorOpen.kt")
public void testPrimaryConstructorOpen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/overrideImplement/PrimaryConstructorOpen.kt");
doTest(fileName);
}
@TestMetadata("PrimaryConstructorOverride.kt")
public void testPrimaryConstructorOverride() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/overrideImplement/PrimaryConstructorOverride.kt");
doTest(fileName);
}
@TestMetadata("PropertyOverride.kt")
public void testPropertyOverride() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/overrideImplement/PropertyOverride.kt");