From f457b1cb7a2bddf08d3613ed050d1e109f8eea5d Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Fri, 13 Jan 2012 11:36:35 +0400 Subject: [PATCH] KT-984 Make structure window work with kotlin files --- .../descriptors/FunctionDescriptorImpl.java | 2 - .../jetbrains/jet/plugin/JetIconProvider.java | 3 + .../JetStructureViewElement.java | 120 +++++++++++++++--- .../JetStructureViewFactory.java | 21 ++- .../structureView/JetStructureViewModel.java | 6 +- 5 files changed, 124 insertions(+), 28 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java index b41e489a52a..83758f56700 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java @@ -5,7 +5,6 @@ import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver; @@ -188,5 +187,4 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorImpl i public R accept(DeclarationDescriptorVisitor visitor, D data) { return visitor.visitFunctionDescriptor(this, data); } - } diff --git a/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java b/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java index f0ce96accde..aea804cccc5 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java @@ -21,6 +21,9 @@ public class JetIconProvider extends IconProvider { @Override public Icon getIcon(@NotNull PsiElement psiElement, int flags) { + if (psiElement instanceof JetFile) { + return KOTLIN_ICON; + } if (psiElement instanceof JetNamespaceHeader) { return (flags & Iconable.ICON_FLAG_OPEN) != 0 ? PlatformIcons.PACKAGE_OPEN_ICON : PlatformIcons.PACKAGE_ICON; } diff --git a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java index 5d4ce0e93fe..de2ff848a3b 100644 --- a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java +++ b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java @@ -6,8 +6,16 @@ import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.NavigatablePsiElement; +import com.intellij.util.Function; import com.intellij.util.PsiIconUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.resolve.DescriptorRenderer; import javax.swing.*; import java.util.ArrayList; @@ -19,8 +27,17 @@ import java.util.List; public class JetStructureViewElement implements StructureViewTreeElement { private final NavigatablePsiElement myElement; - public JetStructureViewElement(NavigatablePsiElement element) { + // For file context will be updated after each construction + // For other tree sub-elements it's immutable. + private BindingContext context; + + public JetStructureViewElement(NavigatablePsiElement element, BindingContext context) { myElement = element; + this.context = context; + } + + public JetStructureViewElement(JetFile fileElement) { + myElement = fileElement; } @Override @@ -48,13 +65,29 @@ public class JetStructureViewElement implements StructureViewTreeElement { return new ItemPresentation() { @Override public String getPresentableText() { - String name = myElement.getName(); - if (StringUtil.isEmpty(name)) { + String text = ""; + + // Try to find text in correspondent descriptor +// if (myElement instanceof JetDeclaration) { +// JetDeclaration declaration = (JetDeclaration) myElement; +// final DeclarationDescriptor descriptor = +// context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration); +// +// if (descriptor != null) { +// text = getDescriptorTreeText(descriptor); +// } +// } + + if (StringUtil.isEmpty(text)) { + text = myElement.getName(); + } + + if (StringUtil.isEmpty(text)) { if (myElement instanceof JetClassInitializer) { return ""; } } - return name; + return text; } @Override @@ -64,20 +97,26 @@ public class JetStructureViewElement implements StructureViewTreeElement { @Override public Icon getIcon(boolean open) { - return myElement.isValid() - ? PsiIconUtil.getProvidersIcon(myElement, open ? Iconable.ICON_FLAG_OPEN : Iconable.ICON_FLAG_CLOSED) - : null; + if (myElement.isValid()) { + return PsiIconUtil.getProvidersIcon( + myElement, + open ? Iconable.ICON_FLAG_OPEN : Iconable.ICON_FLAG_CLOSED); + } + + return null; } }; } - + @Override public TreeElement[] getChildren() { if (myElement instanceof JetFile) { - return new TreeElement[] { new JetStructureViewElement(myElement) }; - } - else if (myElement instanceof JetFile) { - return wrapDeclarations(((JetFile) myElement).getDeclarations()); + final JetFile jetFile = (JetFile) myElement; + + // TODO: Understand why it significantly reduce responsibility of IDEA during typing + // context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(jetFile); + + return wrapDeclarations(jetFile.getDeclarations()); } else if (myElement instanceof JetClass) { JetClass jetClass = (JetClass) myElement; @@ -89,19 +128,68 @@ public class JetStructureViewElement implements StructureViewTreeElement { } declarations.addAll(jetClass.getDeclarations()); return wrapDeclarations(declarations); - } else if (myElement instanceof JetClassOrObject) { return wrapDeclarations(((JetClassOrObject) myElement).getDeclarations()); } return new TreeElement[0]; } - - private static TreeElement[] wrapDeclarations(List declarations) { + + private TreeElement[] wrapDeclarations(List declarations) { TreeElement[] result = new TreeElement[declarations.size()]; for (int i = 0; i < declarations.size(); i++) { - result[i] = new JetStructureViewElement(declarations.get(i)); + result[i] = new JetStructureViewElement(declarations.get(i), context); } return result; } + + public static String getDescriptorTreeText(@NotNull DeclarationDescriptor descriptor) { + StringBuilder textBuilder; + + if (descriptor instanceof FunctionDescriptor) { + textBuilder = new StringBuilder(); + + FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; + ReceiverDescriptor receiver = functionDescriptor.getReceiverParameter(); + if (receiver.exists()) { + textBuilder.append(DescriptorRenderer.TEXT.renderType(receiver.getType())).append("."); + } + + textBuilder.append(functionDescriptor.getName()); + + String parametersString = StringUtil.join( + functionDescriptor.getValueParameters(), + new Function() { + @Override + public String fun(ValueParameterDescriptor valueParameterDescriptor) { + return valueParameterDescriptor.getName() + ":" + + DescriptorRenderer.TEXT.renderType(valueParameterDescriptor.getOutType()); + } + }, + ","); + + textBuilder.append("(").append(parametersString).append(")"); + + JetType returnType = functionDescriptor.getReturnType(); + textBuilder.append(":").append(DescriptorRenderer.TEXT.renderType(returnType)); + } + else if (descriptor instanceof VariableDescriptor) { + JetType outType = ((VariableDescriptor) descriptor).getOutType(); + + textBuilder = new StringBuilder(descriptor.getName()); + textBuilder.append(":").append(DescriptorRenderer.TEXT.renderType(outType)); + } + else if (descriptor instanceof ClassDescriptor) { + textBuilder = new StringBuilder(descriptor.getName()); + textBuilder + .append(" (") + .append(DescriptorUtils.getFQName(descriptor.getContainingDeclaration())) + .append(")"); + } + else { + return DescriptorRenderer.TEXT.render(descriptor); + } + + return textBuilder.toString(); + } } diff --git a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewFactory.java b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewFactory.java index 5e9d3fd2c63..a7fa2ca7162 100644 --- a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewFactory.java +++ b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewFactory.java @@ -6,6 +6,7 @@ import com.intellij.ide.structureView.TreeBasedStructureViewBuilder; import com.intellij.lang.PsiStructureViewFactory; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetFile; /** * @author yole @@ -13,12 +14,18 @@ import org.jetbrains.annotations.NotNull; public class JetStructureViewFactory implements PsiStructureViewFactory { @Override public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) { - return new TreeBasedStructureViewBuilder() { - @NotNull - @Override - public StructureViewModel createStructureViewModel() { - return new JetStructureViewModel(psiFile); - } - }; + if (psiFile instanceof JetFile) { + final JetFile file = (JetFile) psiFile; + + return new TreeBasedStructureViewBuilder() { + @NotNull + @Override + public StructureViewModel createStructureViewModel() { + return new JetStructureViewModel(file); + } + }; + } + + return null; } } diff --git a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewModel.java b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewModel.java index 6a1f5167d35..9a5954cd346 100644 --- a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewModel.java +++ b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewModel.java @@ -1,16 +1,16 @@ package org.jetbrains.jet.plugin.structureView; import com.intellij.ide.structureView.StructureViewModelBase; -import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetFile; /** * @author yole */ public class JetStructureViewModel extends StructureViewModelBase { - public JetStructureViewModel(@NotNull PsiFile psiFile) { - super(psiFile, new JetStructureViewElement(psiFile)); + public JetStructureViewModel(@NotNull JetFile jetFile) { + super(jetFile, new JetStructureViewElement(jetFile)); withSuitableClasses(JetDeclaration.class); } }