PsiReference () { final PsiDocComment comment = PsiTreeUtil.getParentOfType(this, PsiDocComment.class); if (comment == null) return null; final PsiJavaDocumentedElement owner = comment.getOwner(); if (!(owner instanceof PsiMethod) && !(owner instanceof PsiClass)) return null; ASTNode valueToken = getValueToken(); if (valueToken == null) return null; final String name = valueToken.getText(); boolean isTypeParamRef = isTypeParamRef(); PsiElement target = ContainerUtil.find(getAllParameters(comment), param -> isTypeParamRef == param instanceof PsiTypeParameter && name.equals(param.getName())); TextRange range = TextRange.from(valueToken.getPsi().getStartOffsetInParent(), valueToken.getTextLength()); return new PsiReferenceBase<PsiElement>(this, range) { @Override public PsiElement resolve() { return target; } @Override public PsiElement handleElementRename(@NotNull String newElementName) { final CharTable charTableByTree = SharedImplUtil.findCharTableByTree(getNode()); LeafElement newElement = Factory.createSingleLeafElement(JavaDocTokenType.DOC_TAG_VALUE_TOKEN, newElementName, charTableByTree, getManager()); replaceChild(valueToken, newElement); return PsiDocParamRef.this; } @Override public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { if (isReferenceTo(element)) return PsiDocParamRef.this; if(!(element instanceof PsiParameter)) { throw new IncorrectOperationException("Unsupported operation"); } return handleElementRename(((PsiParameter)element).getName()); } @Override public boolean isReferenceTo(@NotNull PsiElement element) { if (!(element instanceof PsiNamedElement)) return false; PsiNamedElement namedElement = (PsiNamedElement)element; if (!getCanonicalText().equals(namedElement.getName())) return false; return getManager().areElementsEquivalent(resolve(), element); } }; }