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);
}
}
Please sign in to leave a comment.
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
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
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
"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
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.