From e53d1773ae1916b60b7338a687c3084754c84349 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 27 Aug 2013 22:29:47 +0400 Subject: [PATCH] Support navigation to get/set methods of a property delegate, if they are in the source code --- .../jet/lang/psi/JetPropertyDelegate.java | 23 +++ ...JetPropertyDelegationMethodsReference.java | 144 ++++++++++++++++++ .../references/JetReferenceContributor.java | 14 +- 3 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/references/JetPropertyDelegationMethodsReference.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPropertyDelegate.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPropertyDelegate.java index 37af4195c42..dcbe675a49a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPropertyDelegate.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPropertyDelegate.java @@ -17,8 +17,12 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiReference; +import com.intellij.psi.PsiReferenceService; +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lexer.JetTokens; public class JetPropertyDelegate extends JetElementImpl { public JetPropertyDelegate(@NotNull ASTNode node) { @@ -30,6 +34,19 @@ public class JetPropertyDelegate extends JetElementImpl { return findChildByClass(JetExpression.class); } + @Override + public PsiReference getReference() { + PsiReference[] references = getReferences(); + if (references.length == 1) return references[0]; + return null; + } + + @NotNull + @Override + public PsiReference[] getReferences() { + return ReferenceProvidersRegistry.getReferencesFromProviders(this, PsiReferenceService.Hints.NO_HINTS); + } + @Override public void accept(@NotNull JetVisitorVoid visitor) { visitor.visitPropertyDelegate(this); @@ -39,4 +56,10 @@ public class JetPropertyDelegate extends JetElementImpl { public R accept(@NotNull JetVisitor visitor, D data) { return visitor.visitPropertyDelegate(this, data); } + + @NotNull + public ASTNode getByKeywordNode() { + //noinspection ConstantConditions + return getNode().findChildByType(JetTokens.BY_KEYWORD); + } } diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetPropertyDelegationMethodsReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetPropertyDelegationMethodsReference.java new file mode 100644 index 00000000000..c67eac7365c --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/references/JetPropertyDelegationMethodsReference.java @@ -0,0 +1,144 @@ +/* + * Copyright 2010-2013 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.references; + +import com.beust.jcommander.internal.Lists; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetProperty; +import org.jetbrains.jet.lang.psi.JetPropertyDelegate; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; + +import java.util.List; + +public class JetPropertyDelegationMethodsReference implements PsiPolyVariantReference { + + public static PsiReference[] create(@NotNull JetPropertyDelegate delegate) { + return new PsiReference[] { new JetPropertyDelegationMethodsReference(delegate) }; + } + + private final JetPropertyDelegate element; + + private JetPropertyDelegationMethodsReference(@NotNull JetPropertyDelegate element) { + this.element = element; + } + + @NotNull + @Override + public ResolveResult[] multiResolve(boolean incompleteCode) { + JetProperty property = PsiTreeUtil.getParentOfType(element, JetProperty.class); + if (property == null) { + return ResolveResult.EMPTY_ARRAY; + } + + BindingContext context = AnalyzerFacadeWithCache.getContextForElement(element); + + DeclarationDescriptor descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property); + if (!(descriptor instanceof PropertyDescriptor)) { + return ResolveResult.EMPTY_ARRAY; + } + + List results = Lists.newArrayList(); + + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + addResultsForAccessor(context, results, propertyDescriptor.getGetter()); + addResultsForAccessor(context, results, propertyDescriptor.getSetter()); + + return results.toArray(new ResolveResult[results.size()]); + } + + private static void addResultsForAccessor(BindingContext context, List results, PropertyAccessorDescriptor accessor) { + if (accessor != null) { + ResolvedCall resolvedCall = context.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor); + if (resolvedCall != null) { + FunctionDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); + + PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resultingDescriptor); + if (declaration != null) { + results.add(new PsiElementResolveResult(declaration, true)); + } + } + } + } + + @Override + public PsiElement getElement() { + return element; + } + + @Override + public TextRange getRangeInElement() { + ASTNode byKeywordNode = element.getByKeywordNode(); + int offset = byKeywordNode.getPsi().getStartOffsetInParent(); + return new TextRange(offset, offset + byKeywordNode.getTextLength()); + } + + @Nullable + @Override + public PsiElement resolve() { + ResolveResult[] results = multiResolve(false); + if (results.length == 1) return results[0].getElement(); + return null; + } + + @NotNull + @Override + public String getCanonicalText() { + return "get"; + } + + @Override + public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { + throw new IncorrectOperationException(); + } + + @Override + public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { + throw new IncorrectOperationException(); + } + + @Override + public boolean isReferenceTo(PsiElement element) { + if (element == null) return false; + + ResolveResult[] results = multiResolve(false); + for (ResolveResult result : results) { + if (element.equals(result.getElement())) return true; + } + return false; + } + + @NotNull + @Override + public Object[] getVariants() { + return EMPTY_ARRAY; + } + + @Override + public boolean isSoft() { + return false; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetReferenceContributor.java b/idea/src/org/jetbrains/jet/plugin/references/JetReferenceContributor.java index 405440eb192..21aaf63e232 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetReferenceContributor.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetReferenceContributor.java @@ -19,10 +19,7 @@ package org.jetbrains.jet.plugin.references; import com.intellij.psi.*; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetArrayAccessExpression; -import org.jetbrains.jet.lang.psi.JetCallExpression; -import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; -import org.jetbrains.jet.lang.psi.JetThisReferenceExpression; +import org.jetbrains.jet.lang.psi.*; import static com.intellij.patterns.PlatformPatterns.psiElement; @@ -64,5 +61,14 @@ public class JetReferenceContributor extends PsiReferenceContributor { return JetInvokeFunctionReference.create((JetCallExpression) element); } }); + + registrar.registerReferenceProvider(psiElement(JetPropertyDelegate.class), + new PsiReferenceProvider() { + @NotNull + @Override + public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext processingContext) { + return JetPropertyDelegationMethodsReference.create((JetPropertyDelegate) element); + } + }); } }