void (@NotNull Project project, PsiDocTag tag) { final PsiMember member = PsiTreeUtil.getParentOfType(tag, PsiMember.class); LOG.assertTrue(member != null); @NonNls String annotationName = getFQAnnotationName(tag); final StringBuilder annotationText = new StringBuilder("@"); annotationText.append(annotationName); final PsiClass annotationClass = DumbService.getInstance(project) .computeWithAlternativeResolveEnabled(() -> JavaPsiFacade.getInstance(member.getProject()) .findClass(annotationName, member.getResolveScope())); PsiElement[] dataElements = tag.getDataElements(); if (dataElements.length > 1) { annotationText.append('('); } if (annotationClass != null) { for (PsiMethod attribute : annotationClass.getMethods()) { boolean stripQuotes = false; PsiType returnType = attribute.getReturnType(); if (returnType instanceof PsiPrimitiveType) { stripQuotes = true; } for (int i = 0; i < dataElements.length; i++) { String text = dataElements[i].getText(); int equals = text.indexOf('='); String value; final String key = equals == -1 ? text : text.substring(0, equals).trim(); if (!key.equals(attribute.getName())) continue; annotationText.append(key).append(" = "); if (equals == -1) { //no equals, so we look in the next token String next = dataElements[++i].getText().trim(); //it's an equals by itself if (next.length() == 1) { value = dataElements[++i].getText().trim(); } else { //otherwise, it's foo =bar, so we strip equals value = next.substring(1).trim(); } } else { //check if the value is in the first bit too if (equals < text.length() - 1) { //we have stuff after equals, great value = text.substring(equals + 1).trim(); } else { //nothing after equals, so we just get the next element value = dataElements[++i].getText().trim(); } } if (stripQuotes && value.charAt(0) == '\"') { value = value.substring(1, value.length() - 1); } annotationText.append(value); } } } if (dataElements.length > 1) { annotationText.append(')'); } try { PsiModifierList modifierList = member.getModifierList(); PsiAnnotation annotation = JavaPsiFacade.getElementFactory(tag.getProject()).createAnnotationFromText(annotationText.toString(), member); final PsiElement inserted = modifierList.addBefore(annotation, modifierList.getFirstChild()); JavaCodeStyleManager.getInstance(project).shortenClassReferences(inserted); final PsiDocComment docComment = PsiTreeUtil.getParentOfType(tag, PsiDocComment.class); LOG.assertTrue(docComment != null); //cleanup tag.delete(); for (PsiElement element : docComment.getChildren()) { //if it's anything other than a doc token, then it must stay if (element instanceof PsiWhiteSpace) continue; if (!(element instanceof PsiDocToken docToken)) return; if (docToken.getTokenType() == JavaDocTokenType.DOC_COMMENT_DATA && !docToken.getText().trim().isEmpty()) { return; } } //at this point, our doc don't have non-empty comments, nor any tags, so we can delete it. docComment.delete(); } catch (IncorrectOperationException e) { LOG.error(e); } }