TextRange (@NotNull Project project, @NotNull ASTNode element, @NotNull final TextRange markedRange) { TextRange resultTextRange = markedRange; final PsiElement elementPsi = element.getPsi(); assert elementPsi.isValid(); final PsiFile file = elementPsi.getContainingFile(); boolean shouldFormat = markedRange.contains(element.getTextRange()); if (shouldFormat) { final ASTNode rangeAnchor; // There are two possible cases: // 1. Given element correspond to comment's owner (e.g. field or method); // 2. Given element corresponds to comment itself; // However, doc comment formatter replaces old comment with the new one, hence, old element becomes invalid. That's why we need // to calculate text length delta not for the given comment element (it's invalid because removed from the AST tree) but for // its parent. if (elementPsi instanceof PsiDocComment) { rangeAnchor = element.getTreeParent(); } else { rangeAnchor = element; } TextRange before = rangeAnchor.getTextRange(); new CommentFormatter(file).processComment(element); int deltaRange = rangeAnchor.getTextRange().getLength() - before.getLength(); resultTextRange = new TextRange(markedRange.getStartOffset(), markedRange.getEndOffset() + deltaRange); } // If element is Psi{Method, Field, DocComment} and was formatted there is no reason to continue - we formatted all possible javadocs. // If element is out of range its children are also out of range. So in both cases formatting is finished. It's just for optimization. if ((shouldFormat && (elementPsi instanceof PsiMethod || elementPsi instanceof PsiField || elementPsi instanceof PsiDocComment)) || markedRange.getEndOffset() < element.getStartOffset()) { return resultTextRange; } ASTNode current = element.getFirstChildNode(); while (current != null) { // When element is PsiClass its PsiDocComment is formatted up to this moment, so we didn't need to format it again. if (!(shouldFormat && current.getPsi() instanceof PsiDocComment && elementPsi instanceof PsiClass)) { resultTextRange = formatCommentsInner(project, current, resultTextRange); } current = current.getTreeNext(); } return resultTextRange; }