My PsiReferenceContributor unintentional prevent renaming of Java methods

My good people, 

I have implemented my own PsiReferenceContributor for reference support between Camel Route bean call and the method is calling, so it can jump to the declaration. But for some reason I don't understand it also prevent renaming of Java methods in general :-| ?

This is a typical Camel Route with bean reference, where I jump to "myBeanMethod1" or "myLocalBean"

@Override
public void configure() throws Exception {
from("file:inbox")
.bean(MyBeanClass.class,"myBeanMethod1")
.bean(JavaCamelRouteBuilder.class,"myLocalBean")
.to("file:outbox");

from("file:outbox")
.to("file:inbox");
}

The PsiReferenceContributor :

public class BeanReferenceContributor extends PsiReferenceContributor {
@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
final PsiElementPattern.Capture<PsiLiteralExpression> pattern = PlatformPatterns.psiElement(PsiLiteralExpression.class)
.withParent(PsiExpressionList.class);
registrar.registerReferenceProvider(pattern,
new PsiReferenceProvider() {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
@NotNull ProcessingContext
context) {
if (!ServiceManager.getService(element.getProject(), CamelService.class).isCamelPresent()) {
return PsiReference.EMPTY_ARRAY;
}

final PsiElement beanClassElement = getCamelIdeaUtils().getBeanPsiElement(element);
if (beanClassElement != null) {
PsiElement psiClass = beanClassElement.getReference().resolve();
final PsiLiteral beanNameElement = PsiTreeUtil.findChildOfType(PsiTreeUtil.getParentOfType(beanClassElement, PsiExpressionList.class), PsiLiteral.class);
String methodName = beanNameElement.getText().replace("\"", "");
if (! methodName.isEmpty()) {
return new PsiReference[] {new MethodReference(psiClass, methodName, new TextRange(1, methodName.length() + 1))};
}
}
return PsiReference.EMPTY_ARRAY;
}
});
}

private static CamelIdeaUtils getCamelIdeaUtils() {
return ServiceManager.getService(CamelIdeaUtils.class);
}

}

public class MethodReference extends PsiReferenceBase<PsiElement> implements PsiPolyVariantReference {

private String methodName;

MethodReference(PsiElement element, String methodName, TextRange textRange) {
super(element, textRange);
this.methodName = methodName;
}

@NotNull
@Override
public ResolveResult[] multiResolve(boolean b) {
List<ResolveResult> results = new ArrayList<>();
final PsiMethod[] methodsByName = ((PsiClass) getElement()).findMethodsByName(methodName, true);
for (PsiMethod psiMethod : methodsByName) {
final boolean isPrivate = getCamelIdeaUtils().isOneOfModifierType(psiMethod, JvmModifier.PRIVATE, JvmModifier.ABSTRACT);

if (!isPrivate) {
if (getCamelIdeaUtils().isAnnotatedWithHandler(psiMethod)) {
return new ResolveResult[] {new PsiElementResolveResult(psiMethod)};
}
results.add(new PsiElementResolveResult(psiMethod));
}
}
return results.toArray(new ResolveResult[results.size()]);
}

@Nullable
@Override
public PsiElement resolve() {
ResolveResult[] resolveResults = multiResolve(false);
return resolveResults.length == 1 ? resolveResults[0].getElement() : null;
}

@NotNull
@Override
public Object[] getVariants() {
return new Object[0];
}

private static CamelIdeaUtils getCamelIdeaUtils() {
return ServiceManager.getService(CamelIdeaUtils.class);
}
}
1

Hi Flemming,

it should not prevent method renaming. Please attach the idea.log of the corresponding IDEA instance and the screenshot what happens when you start renaming the method

Thanks,

Anna

0
Avatar
Permanently deleted user

Hi Anna

Thanks for getting back!

I have attached the log and GIF showing what it does when I rename a method

https://gist.github.com/fharms/8508b4a9b74638d434025a371adde628 

Thanks,

Flemming

0

The method is recognized to be a target for your reference and then it means that you need to provide a way to rename the reference itself, corresponding exception in the log

2018-02-12 13:51:21,929 [ 23899] ERROR - .intellij.psi.PsiReferenceBase - Cannot find manipulator for PsiClass:JavaCamelRouteBuilder in PsiClass:JavaCamelRouteBuilder:(1,12) class class org.apache.camel.idea.refereance.MethodReference

  java.lang.Throwable: Cannot find manipulator for PsiClass:JavaCamelRouteBuilder in PsiClass:JavaCamelRouteBuilder:(1,12) class class org.apache.camel.idea.refereance.MethodReference
  at com.intellij.openapi.diagnostic.Logger.error(Logger.java:136)
  at com.intellij.psi.PsiReferenceBase.getManipulator(PsiReferenceBase.java:139)
  at com.intellij.psi.PsiReferenceBase.handleElementRename(PsiReferenceBase.java:115)
  at com.intellij.refactoring.rename.RenameJavaMethodProcessor.processRef(RenameJavaMethodProcessor.java:143)
  at com.intellij.refactoring.rename.RenameJavaMethodProcessor.renameElement(RenameJavaMethodProcessor.java:95)
  at com.intellij.refactoring.rename.RenameUtil.doRename(RenameUtil.java:188)
  at com.intellij.refactoring.rename.RenameProcessor.performRefactoring(RenameProcessor.java:380)
  at com.intellij.refactoring.BaseRefactoringProcessor.lambda$doRefactoring$11(BaseRefactoringProcessor.java:475)
  at com.intellij.refactoring.BaseRefactoringProcessor.lambda$doRefactoring$12(BaseRefactoringProcessor.java:486)
  at com.intellij.openapi.application.impl.ApplicationImpl.lambda$runWriteActionWithProgressInDispatchThread$15(ApplicationImpl.java:965)
  at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$1(CoreProgressManager.java:157)
0
Avatar
Permanently deleted user

"you need to provide a way to rename the reference itself"

Could you point my in a direction where to look for a guide, documentation or examples.

/Flemming

0

You need to implement com.intellij.psi.PsiReference#handleElementRename or register com.intellij.psi.ElementManipulator (see com.intellij.psi.impl.source.resolve.reference.impl.manipulators.XmlAttributeManipulator for an example)

The idea is - you need to update the text of the element under the reference given a new name of a reference target.

1

请先登录再写评论。