Added implements/overrides line marks for properties.

This commit is contained in:
Evgeny Gerashchenko
2012-03-29 18:35:04 +04:00
parent f57ebac1ff
commit 6aadf4400d
@@ -28,15 +28,16 @@ import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.IconLoader;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiUtilBase; import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Function; import com.intellij.util.Function;
import com.intellij.util.PsiNavigateUtil; import com.intellij.util.PsiNavigateUtil;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.Modality; import org.jetbrains.jet.lang.descriptors.Modality;
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.resolve.DescriptorRenderer; import org.jetbrains.jet.resolve.DescriptorRenderer;
@@ -55,45 +56,46 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
public static final Icon IMPLEMENTING_MARK = IconLoader.getIcon("/gutter/implementingMethod.png"); public static final Icon IMPLEMENTING_MARK = IconLoader.getIcon("/gutter/implementingMethod.png");
@Override @Override
public LineMarkerInfo getLineMarkerInfo(PsiElement element) { public LineMarkerInfo getLineMarkerInfo(final PsiElement element) {
JetFile file = (JetFile)element.getContainingFile(); JetFile file = (JetFile)element.getContainingFile();
if (file == null) return null; if (file == null) return null;
if (!(element instanceof JetNamedFunction)) return null; if (!(element instanceof JetNamedFunction || element instanceof JetProperty)) return null;
JetNamedFunction jetFunction = (JetNamedFunction)element;
final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
final SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, jetFunction); final DeclarationDescriptor descriptor =
if (functionDescriptor == null) return null; bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
final Set<? extends FunctionDescriptor> overriddenFunctions = functionDescriptor.getOverriddenDescriptors(); if (!(descriptor instanceof CallableMemberDescriptor)) return null;
if (overriddenFunctions.size() == 0) return null; final Set<? extends CallableMemberDescriptor> overriddenMembers = ((CallableMemberDescriptor)descriptor).getOverriddenDescriptors();
if (overriddenMembers.size() == 0) return null;
boolean allOverriddenAbstract = true; boolean allOverriddenAbstract = true;
for (FunctionDescriptor function : overriddenFunctions) { for (CallableMemberDescriptor function : overriddenMembers) {
allOverriddenAbstract &= function.getModality() == Modality.ABSTRACT; allOverriddenAbstract &= function.getModality() == Modality.ABSTRACT;
} }
final String implementsOrOverrides = allOverriddenAbstract ? "implements" : "overrides"; final String implementsOrOverrides = allOverriddenAbstract ? "implements" : "overrides";
final String memberKind = element instanceof JetNamedFunction ? "function" : "property";
return new LineMarkerInfo<JetNamedFunction>( return new LineMarkerInfo<PsiElement>(
jetFunction, element,
jetFunction.getTextOffset(), element.getTextOffset(),
allOverriddenAbstract ? IMPLEMENTING_MARK : OVERRIDING_MARK, allOverriddenAbstract ? IMPLEMENTING_MARK : OVERRIDING_MARK,
Pass.UPDATE_ALL, Pass.UPDATE_ALL,
new Function<JetNamedFunction, String>() { new Function<PsiElement, String>() {
@Override @Override
public String fun(JetNamedFunction jetFunction) { public String fun(PsiElement element) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append(DescriptorRenderer.HTML.render(functionDescriptor)); builder.append(DescriptorRenderer.HTML.render(descriptor));
int overrideCount = overriddenFunctions.size(); int overrideCount = overriddenMembers.size();
if (overrideCount >= 1) { if (overrideCount >= 1) {
builder.append(" ").append(implementsOrOverrides).append(" "); builder.append(" ").append(implementsOrOverrides).append(" ");
builder.append(DescriptorRenderer.HTML.render(overriddenFunctions.iterator().next())); builder.append(DescriptorRenderer.HTML.render(overriddenMembers.iterator().next()));
} }
if (overrideCount > 1) { if (overrideCount > 1) {
int count = overrideCount - 1; int count = overrideCount - 1;
builder.append(" and ").append(count).append(" other function"); builder.append(" and ").append(count).append(" other ").append(memberKind);
if (count > 1) { if (count > 1) {
builder.append("s"); builder.append("s");
} }
@@ -102,13 +104,13 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
return builder.toString(); return builder.toString();
} }
}, },
new GutterIconNavigationHandler<JetNamedFunction>() { new GutterIconNavigationHandler<PsiElement>() {
@Override @Override
public void navigate(MouseEvent event, JetNamedFunction elt) { public void navigate(MouseEvent event, PsiElement elt) {
if (overriddenFunctions.isEmpty()) return; if (overriddenMembers.isEmpty()) return;
final List<PsiElement> list = Lists.newArrayList(); final List<PsiElement> list = Lists.newArrayList();
for (FunctionDescriptor overriddenFunction : overriddenFunctions) { for (CallableMemberDescriptor overriddenMember : overriddenMembers) {
PsiElement declarationPsiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, overriddenFunction); PsiElement declarationPsiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, overriddenMember);
list.add(declarationPsiElement); list.add(declarationPsiElement);
} }
if (list.isEmpty()) { if (list.isEmpty()) {
@@ -124,7 +126,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
PsiNavigateUtil.navigate(list.iterator().next()); PsiNavigateUtil.navigate(list.iterator().next());
} }
else { else {
final JBPopup popup = NavigationUtil.getPsiElementPopup(PsiUtilBase.toPsiElementArray(list), new DefaultPsiElementCellRenderer() { final JBPopup popup = NavigationUtil.getPsiElementPopup(PsiUtilCore.toPsiElementArray(list), new DefaultPsiElementCellRenderer() {
@Override @Override
public String getElementText(PsiElement element) { public String getElementText(PsiElement element) {
if (element instanceof JetNamedFunction) { if (element instanceof JetNamedFunction) {
@@ -133,7 +135,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
} }
return super.getElementText(element); return super.getElementText(element);
} }
}, DescriptorRenderer.HTML.render(functionDescriptor)); }, DescriptorRenderer.HTML.render(descriptor));
if (event != null) { if (event != null) {
popup.show(new RelativePoint(event)); popup.show(new RelativePoint(event));
} }