Show members from supertypes in file structure view (KT-4448)

#KT-4448 Fixed
This commit is contained in:
Nikolay Krasko
2014-05-26 16:48:45 +04:00
parent d941deb17c
commit f1f13d1f2a
19 changed files with 234 additions and 8 deletions

View File

@@ -0,0 +1,8 @@
<root>
<item
name='com.intellij.ide.util.treeView.smartTree.NodeProvider java.util.Collection&lt;T&gt; provideNodes(com.intellij.ide.util.treeView.smartTree.TreeElement)'>
<annotation name='kotlin.jvm.KotlinSignature'>
<val name="value" val="&quot;fun provideNodes(node: TreeElement): Collection&lt;T&gt;&quot;"/>
</annotation>
</item>
</root>

View File

@@ -573,7 +573,7 @@ fun main(args: Array<String>) {
}
testClass(javaClass<AbstractKotlinFileStructureTest>()) {
model("structureView/fileStructure")
model("structureView/fileStructure", pattern = """^([^\.]+)\.kt$""")
}
testClass(javaClass<AbstractExpressionSelectionTest>()) {

View File

@@ -47,13 +47,27 @@ public class JetStructureViewElement implements StructureViewTreeElement, Colore
private String elementText;
private Icon icon;
private final boolean isInherited;
public JetStructureViewElement(@NotNull NavigatablePsiElement element) {
public JetStructureViewElement(@NotNull NavigatablePsiElement element, @NotNull DeclarationDescriptor descriptor, boolean isInherited) {
this.element = element;
this.isInherited = isInherited;
if (!(element instanceof JetElement)) {
// Avoid storing descriptor in fields
elementText = getElementText(element, descriptor);
icon = getElementIcon(element, descriptor);
}
}
public JetStructureViewElement(@NotNull NavigatablePsiElement element, boolean isInherited) {
this.element = element;
this.isInherited = isInherited;
}
public JetStructureViewElement(@NotNull JetFile fileElement) {
element = fileElement;
isInherited = false;
}
@NotNull
@@ -94,7 +108,7 @@ public class JetStructureViewElement implements StructureViewTreeElement, Colore
return ArrayUtil.toObjectArray(ContainerUtil.map(childrenDeclarations, new Function<JetDeclaration, TreeElement>() {
@Override
public TreeElement fun(JetDeclaration declaration) {
return new JetStructureViewElement(declaration);
return new JetStructureViewElement(declaration, false);
}
}), TreeElement.class);
}
@@ -102,9 +116,15 @@ public class JetStructureViewElement implements StructureViewTreeElement, Colore
@Nullable
@Override
public TextAttributesKey getTextAttributesKey() {
if (isInherited()) {
return CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES;
}
if (element instanceof JetModifierListOwner && JetPsiUtil.isDeprecated((JetModifierListOwner) element)) {
return CodeInsightColors.DEPRECATED_ATTRIBUTES;
}
return null;
}
@@ -134,6 +154,10 @@ public class JetStructureViewElement implements StructureViewTreeElement, Colore
return icon;
}
public boolean isInherited() {
return isInherited;
}
@Nullable
private DeclarationDescriptor getDescriptor() {
if (!(element.isValid() && element instanceof JetDeclaration)) {
@@ -175,6 +199,7 @@ public class JetStructureViewElement implements StructureViewTreeElement, Colore
return Collections.emptyList();
}
@Nullable
private static Icon getElementIcon(@NotNull NavigatablePsiElement navigatablePsiElement, @Nullable DeclarationDescriptor descriptor) {
if (descriptor != null) {
return JetDescriptorIconProvider.getIcon(descriptor, navigatablePsiElement, Iconable.ICON_FLAG_VISIBILITY);

View File

@@ -17,12 +17,19 @@
package org.jetbrains.jet.plugin.structureView;
import com.intellij.ide.structureView.StructureViewModelBase;
import com.intellij.ide.util.treeView.smartTree.NodeProvider;
import com.intellij.ide.util.treeView.smartTree.Sorter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import java.util.Arrays;
import java.util.Collection;
public class JetStructureViewModel extends StructureViewModelBase {
private static final Collection<NodeProvider> NODE_PROVIDERS = Arrays.<NodeProvider>asList(
new KotlinInheritedMembersNodeProvider());
private static final Sorter[] sorters = new Sorter[] {Sorter.ALPHA_SORTER};
public JetStructureViewModel(@NotNull JetFile jetFile) {
@@ -30,6 +37,12 @@ public class JetStructureViewModel extends StructureViewModelBase {
withSuitableClasses(JetDeclaration.class);
}
@NotNull
@Override
public Collection<NodeProvider> getNodeProviders() {
return NODE_PROVIDERS;
}
@NotNull
@Override
public Sorter[] getSorters() {

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2010-2014 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.jet.plugin.structureView
import com.intellij.ide.util.treeView.smartTree.TreeElement
import com.intellij.ide.util.InheritedMembersNodeProvider
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import java.util.ArrayList
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor
import com.intellij.psi.NavigatablePsiElement
import org.jetbrains.jet.lang.psi.JetClassOrObject
public class KotlinInheritedMembersNodeProvider: InheritedMembersNodeProvider<TreeElement>() {
override fun provideNodes(node: TreeElement): Collection<TreeElement> {
if (node !is JetStructureViewElement) return listOf()
val element = node.getElement()
if (element !is JetClassOrObject) return listOf()
[suppress("USELESS_CAST")] // KT-3996 Workaround
val project = (element as NavigatablePsiElement).getProject()
val context = AnalyzerFacadeWithCache.getContextForElement(element)
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, element]
if (descriptor !is ClassifierDescriptor) return listOf()
val children = ArrayList<TreeElement>()
val defaultType = descriptor.getDefaultType()
for (memberDescriptor in defaultType.getMemberScope().getAllDescriptors()) {
if (memberDescriptor !is CallableMemberDescriptor) continue
if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue
val superTypeMember = DescriptorToDeclarationUtil.getDeclaration(project, memberDescriptor, context)
if (superTypeMember is NavigatablePsiElement) {
children.add(JetStructureViewElement(superTypeMember, memberDescriptor, true))
}
}
return children
}
}

View File

@@ -0,0 +1,6 @@
open class A {
class I1
inner class I2
fun foo() {}
}

View File

@@ -0,0 +1,6 @@
-InheritedInnerClasses.kt
-B : A
equals(Any?): Boolean
foo(): Unit
hashCode(): Int
toString(): String

View File

@@ -0,0 +1,5 @@
class B: A()
// Inner classes are not shown, same to Java
// WITH_INHERITED

View File

@@ -0,0 +1,15 @@
-InheritedJavaMembers.kt
-InheritedJavaMembers : Callable<String>
call(): String?
clone(): Any
equals(Any?): Boolean
finalize(): Unit
getClass(): Class<out Any?>
hashCode(): Int
notify(): Unit
notifyAll(): Unit
test(): Unit
toString(): String
wait(): Unit
wait(Long): Unit
wait(Long, Int): Unit

View File

@@ -0,0 +1,8 @@
import java.util.concurrent.Callable
public abstract class InheritedJavaMembers() : Callable<String> {
fun test() {
}
}
// WITH_INHERITED

View File

@@ -0,0 +1,8 @@
-InheritedLocalKotlin.kt
-A : TA
equals(Any?): Boolean
hashCode(): Int
some(): Unit
toString(): String
-B : TA
some(): Unit

View File

@@ -0,0 +1,12 @@
trait TA {
fun some()
}
class A : TA {
override fun some() {
}
}
abstract class B : TA
// WITH_INHERITED

View File

@@ -1,2 +1,6 @@
-InheritedMembers.kt
Test
-Test
equals(Any?): Boolean
hashCode(): Int
test(): Unit
toString(): String

View File

@@ -1,3 +1,7 @@
class Test {
class Test: Runable {
fun test() {
}
}
}
// WITH_INHERITED

View File

@@ -0,0 +1,7 @@
trait First<T> {
fun foo(a: T)
}
trait Second<U> : First<Int> {
val a: U
}

View File

@@ -0,0 +1,7 @@
-InheritedMembersWithSubstitutedTypes.kt
-Third : Second<String>
a: U
equals(Any?): Boolean
foo(T): Unit
hashCode(): Int
toString(): String

View File

@@ -0,0 +1,5 @@
trait Third: Second<String>
// Original type names are shown in members, behaviour is same to Java.
// WITH_INHERITED

View File

@@ -27,12 +27,14 @@ import com.intellij.ide.util.FileStructurePopup
import com.intellij.ide.actions.ViewStructureAction
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
import org.jetbrains.jet.JetTestUtils
import org.jetbrains.jet.InTextDirectivesUtils
import org.jetbrains.jet.test.util.configureWithExtraFile
public abstract class AbstractKotlinFileStructureTest : JetLightCodeInsightFixtureTestCase() {
override fun getTestDataPath() = PluginTestCaseBase.getTestDataPathBase() + "/structureView/fileStructure"
public fun doTest(path: String) {
myFixture.configureByFile(path)
myFixture.configureWithExtraFile(path)
val textEditor = TextEditorProvider.getInstance()!!.getTextEditor(myFixture.getEditor())
val popup = ViewStructureAction.createPopup(myFixture.getProject(), textEditor)
@@ -43,10 +45,19 @@ public abstract class AbstractKotlinFileStructureTest : JetLightCodeInsightFixtu
popup.getTreeBuilder().getUi()!!.getUpdater()!!.setPassThroughMode(true)
popup.update()
popup.setup()
val popupText = PlatformTestUtil.print(popup.getTree(), false)
JetTestUtils.assertEqualsToFile(File("${FileUtil.getNameWithoutExtension(path)}.after"), popupText)
}
protected fun FileStructurePopup.setup() {
val fileText = FileUtil.loadFile(File(getTestDataPath(), fileName()!!), true)
val withInherited = InTextDirectivesUtils.isDirectiveDefined(fileText, "WITH_INHERITED")
setTreeActionState(javaClass<KotlinInheritedMembersNodeProvider>(), withInherited)
}
public fun FileStructurePopup.update() {
getTreeBuilder().refilter()!!.doWhenProcessed {
getStructure().rebuild()

View File

@@ -33,7 +33,9 @@ import org.jetbrains.jet.plugin.structureView.AbstractKotlinFileStructureTest;
@TestMetadata("idea/testData/structureView/fileStructure")
public class KotlinFileStructureTestGenerated extends AbstractKotlinFileStructureTest {
public void testAllFilesPresentInFileStructure() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/structureView/fileStructure"), Pattern.compile("^(.+)\\.kt$"), true);
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage",
new File("idea/testData/structureView/fileStructure"),
Pattern.compile("^([^\\.]+)\\.kt$"), true);
}
@TestMetadata("EmptyFile.kt")
@@ -41,11 +43,31 @@ public class KotlinFileStructureTestGenerated extends AbstractKotlinFileStructur
doTest("idea/testData/structureView/fileStructure/EmptyFile.kt");
}
@TestMetadata("InheritedInnerClasses.kt")
public void testInheritedInnerClasses() throws Exception {
doTest("idea/testData/structureView/fileStructure/InheritedInnerClasses.kt");
}
@TestMetadata("InheritedJavaMembers.kt")
public void testInheritedJavaMembers() throws Exception {
doTest("idea/testData/structureView/fileStructure/InheritedJavaMembers.kt");
}
@TestMetadata("InheritedLocalKotlin.kt")
public void testInheritedLocalKotlin() throws Exception {
doTest("idea/testData/structureView/fileStructure/InheritedLocalKotlin.kt");
}
@TestMetadata("InheritedMembers.kt")
public void testInheritedMembers() throws Exception {
doTest("idea/testData/structureView/fileStructure/InheritedMembers.kt");
}
@TestMetadata("InheritedMembersWithSubstitutedTypes.kt")
public void testInheritedMembersWithSubstitutedTypes() throws Exception {
doTest("idea/testData/structureView/fileStructure/InheritedMembersWithSubstitutedTypes.kt");
}
@TestMetadata("Render.kt")
public void testRender() throws Exception {
doTest("idea/testData/structureView/fileStructure/Render.kt");