[javadoc] Remove redundant abstract classes; make methods static, minor cleaup

GitOrigin-RevId: 3c5af00a75d01c9eba13bb148a33c6d0246e03c9
This commit is contained in:
Tagir Valeev
2025-05-09 14:45:21 +00:00
committed by intellij-monorepo-bot
parent 76a9727974
commit 7f42c13987
8 changed files with 326 additions and 374 deletions
@@ -69,12 +69,12 @@ public abstract class AbstractBasicJavaSmartEnterProcessor extends SmartEnterPro
private static class TooManyAttemptsException extends Exception {
}
private final AbstractBasicJavadocFixer myJavadocFixer;
private final JavadocFixer myJavadocFixer;
protected AbstractBasicJavaSmartEnterProcessor(@NotNull List<Fixer> fixers,
EnterProcessor @NotNull [] enterProcessors,
EnterProcessor @NotNull [] afterCompletionEnterProcessors,
@NotNull AbstractBasicJavadocFixer thinJavadocFixer,
@NotNull JavadocFixer thinJavadocFixer,
@NotNull EnterProcessor breakerEnterProcessor) {
myBreakerEnterProcessor = breakerEnterProcessor;
ourFixers = fixers;
@@ -106,7 +106,7 @@ public abstract class AbstractBasicJavaSmartEnterProcessor extends SmartEnterPro
document.replaceString(0, document.getTextLength(), textForRollback);
}
catch (Exception e) {
e.printStackTrace();
LOG.error(e);
}
finally {
editor.putUserData(SMART_ENTER_TIMESTAMP, null);
@@ -206,12 +206,12 @@ public abstract class AbstractBasicJavaSmartEnterProcessor extends SmartEnterPro
if (myFirstErrorOffset != Integer.MAX_VALUE) {
editor.getCaretModel().moveToOffset(myFirstErrorOffset);
reformat(editor, atCaret);
reformat(atCaret);
return;
}
final RangeMarker rangeMarker = createRangeMarker(atCaret);
reformat(editor, atCaret);
reformat(atCaret);
commit(editor);
if (!mySkipEnter) {
@@ -357,10 +357,6 @@ public abstract class AbstractBasicJavaSmartEnterProcessor extends SmartEnterPro
editor.getCaretModel().moveToOffset(caretOffset - 1);
}
protected void reformat(@NotNull Editor editor, @Nullable PsiElement elt) {
reformat(elt);
}
private void reformatBlockParentIfNeeded(@NotNull Editor editor, @NotNull PsiFile file) {
commit(editor);
ASTNode block =
@@ -1,112 +0,0 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.editorActions.smartEnter;
import com.intellij.javadoc.AbstractBasicJavadocHelper;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
/**
* Serves as a facade for javadoc smart completion.
* <p/>
* Thread-safe.
*/
public abstract class AbstractBasicJavadocFixer {
private final AbstractBasicJavadocHelper myHelper;
public AbstractBasicJavadocFixer(@NotNull AbstractBasicJavadocHelper helper) { myHelper = helper; }
/**
* Checks if caret of the given editor is located inside javadoc and tries to perform smart completion there in case of the positive
* answer.
*
* @param editor target editor
* @param psiFile PSI file for the document exposed via the given editor
* @return {@code true} if smart completion was performed; {@code false} otherwise
*/
public boolean process(@NotNull Editor editor, @NotNull PsiFile psiFile) {
// Check parameter description completion.
final CaretModel caretModel = editor.getCaretModel();
final Pair<AbstractBasicJavadocHelper.JavadocParameterInfo,List<AbstractBasicJavadocHelper.JavadocParameterInfo>> pair =
myHelper.parse(psiFile, editor, caretModel.getOffset());
if (pair.first == null) {
return false;
}
final AbstractBasicJavadocHelper.JavadocParameterInfo next = findNext(pair.second, pair.first);
if (next == null) {
final int line = pair.first.lastLine + 1;
final Document document = editor.getDocument();
if (line < document.getLineCount()) {
StringBuilder indent = new StringBuilder();
boolean insertIndent = true;
final CharSequence text = document.getCharsSequence();
for (int i = document.getLineStartOffset(line), max = document.getLineEndOffset(line); i < max; i++) {
final char c = text.charAt(i);
if (c == ' ' || c == '\t') {
indent.append(c);
continue;
}
else if (c == '*') {
indent.append("* ");
if (i < max - 1 && text.charAt(i + 1) != '/') {
insertIndent = false;
}
}
indent.append("\n");
break;
}
if (insertIndent) {
document.insertString(document.getLineStartOffset(line), indent);
}
}
moveCaretToTheLineEndIfPossible(editor, line);
return true;
}
if (next.parameterDescriptionStartPosition != null) {
myHelper.navigate(next.parameterDescriptionStartPosition, editor, psiFile.getProject());
}
else {
final LogicalPosition position = myHelper.calculateDescriptionStartPosition(psiFile, pair.second, next);
myHelper.navigate(position, editor, psiFile.getProject());
}
return true;
}
private static void moveCaretToTheLineEndIfPossible(@NotNull Editor editor, int line) {
final Document document = editor.getDocument();
final CaretModel caretModel = editor.getCaretModel();
int offset;
if (line >= document.getLineCount()) {
offset = document.getTextLength();
}
else {
offset = document.getLineEndOffset(line);
}
caretModel.moveToOffset(offset);
}
private static @Nullable AbstractBasicJavadocHelper.JavadocParameterInfo findNext(@NotNull Collection<? extends AbstractBasicJavadocHelper.JavadocParameterInfo> data,
@NotNull AbstractBasicJavadocHelper.JavadocParameterInfo anchor)
{
boolean returnNow = false;
for (AbstractBasicJavadocHelper.JavadocParameterInfo info : data) {
if (returnNow) {
return info;
}
returnNow = info == anchor;
}
return null;
}
}
@@ -1,15 +1,107 @@
package com.intellij.codeInsight.editorActions.smartEnter;
import com.intellij.javadoc.JavadocHelper;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
/**
* Serves as a facade for javadoc smart completion.
* <p/>
* Thread-safe.
*/
public class JavadocFixer extends AbstractBasicJavadocFixer {
public class JavadocFixer {
public JavadocFixer() {
super( new JavadocHelper());
/**
* Checks if caret of the given editor is located inside javadoc and tries to perform smart completion there in case of the positive
* answer.
*
* @param editor target editor
* @param psiFile PSI file for the document exposed via the given editor
* @return {@code true} if smart completion was performed; {@code false} otherwise
*/
public boolean process(@NotNull Editor editor, @NotNull PsiFile psiFile) {
// Check parameter description completion.
final CaretModel caretModel = editor.getCaretModel();
final Pair<JavadocHelper.JavadocParameterInfo, List<JavadocHelper.JavadocParameterInfo>> pair =
JavadocHelper.parse(psiFile, editor, caretModel.getOffset());
if (pair.first == null) {
return false;
}
final JavadocHelper.JavadocParameterInfo next = findNext(pair.second, pair.first);
if (next == null) {
final int line = pair.first.lastLine + 1;
final Document document = editor.getDocument();
if (line < document.getLineCount()) {
StringBuilder indent = new StringBuilder();
boolean insertIndent = true;
final CharSequence text = document.getCharsSequence();
for (int i = document.getLineStartOffset(line), max = document.getLineEndOffset(line); i < max; i++) {
final char c = text.charAt(i);
if (c == ' ' || c == '\t') {
indent.append(c);
continue;
}
else if (c == '*') {
indent.append("* ");
if (i < max - 1 && text.charAt(i + 1) != '/') {
insertIndent = false;
}
}
indent.append("\n");
break;
}
if (insertIndent) {
document.insertString(document.getLineStartOffset(line), indent);
}
}
moveCaretToTheLineEndIfPossible(editor, line);
return true;
}
if (next.parameterDescriptionStartPosition != null) {
JavadocHelper.navigate(next.parameterDescriptionStartPosition, editor, psiFile.getProject());
}
else {
final LogicalPosition position = JavadocHelper.calculateDescriptionStartPosition(psiFile, pair.second, next);
JavadocHelper.navigate(position, editor, psiFile.getProject());
}
return true;
}
private static void moveCaretToTheLineEndIfPossible(@NotNull Editor editor, int line) {
final Document document = editor.getDocument();
final CaretModel caretModel = editor.getCaretModel();
int offset;
if (line >= document.getLineCount()) {
offset = document.getTextLength();
}
else {
offset = document.getLineEndOffset(line);
}
caretModel.moveToOffset(offset);
}
private static @Nullable JavadocHelper.JavadocParameterInfo findNext(@NotNull Collection<? extends JavadocHelper.JavadocParameterInfo> data,
@NotNull JavadocHelper.JavadocParameterInfo anchor)
{
boolean returnNow = false;
for (JavadocHelper.JavadocParameterInfo info : data) {
if (returnNow) {
return info;
}
returnNow = info == anchor;
}
return null;
}
}
@@ -56,7 +56,7 @@ public class MissingLambdaBodyFixer implements Fixer {
processor.insertBracesWithNewLine(editor, offset);
editor.getCaretModel().moveToOffset(offset + 1);
processor.commit(editor);
processor.reformat(editor, psiElement);
processor.reformat(psiElement);
processor.setSkipEnter(BasicJavaAstTreeUtil.is(astNode, BASIC_LAMBDA_EXPRESSION));
}
}
@@ -1,230 +0,0 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.javadoc;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.ParentAwareTokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.intellij.psi.impl.source.BasicJavaDocElementType.*;
public abstract class AbstractBasicJavadocHelper {
private static final String PARAM_TEXT = "param";
public static final Pair<JavadocParameterInfo, List<JavadocParameterInfo>> EMPTY
= new Pair<>(null, Collections.emptyList());
private static final @NotNull ParentAwareTokenSet TAG_TOKEN_SET = ParentAwareTokenSet.create(BASIC_DOC_TAG,
BASIC_DOC_SNIPPET_TAG,
BASIC_DOC_INLINE_TAG);
protected AbstractBasicJavadocHelper() {
}
/**
* Tries to navigate caret at the given editor to the target position inserting missing white spaces if necessary.
*
* @param position target caret position
* @param editor target editor
* @param project target project
*/
public void navigate(@NotNull LogicalPosition position, @NotNull Editor editor, final @NotNull Project project) {
final Document document = editor.getDocument();
final CaretModel caretModel = editor.getCaretModel();
final int endLineOffset = document.getLineEndOffset(position.line);
final LogicalPosition endLinePosition = editor.offsetToLogicalPosition(endLineOffset);
if (endLinePosition.column < position.column && !editor.getSettings().isVirtualSpace() && !editor.isViewer()) {
final String toInsert = StringUtil.repeat(" ", position.column - endLinePosition.column);
ApplicationManager.getApplication().runWriteAction(() -> {
document.insertString(endLineOffset, toInsert);
PsiDocumentManager.getInstance(project).commitDocument(document);
});
}
caretModel.moveToLogicalPosition(position);
}
/**
* Calculates desired position of target javadoc parameter's description start.
*
* @param psiFile PSI holder
* @param data parsed adjacent javadoc parameters
* @param anchor descriptor for the target parameter
* @return logical position that points to the desired parameter description start location
*/
public @NotNull LogicalPosition calculateDescriptionStartPosition(@NotNull PsiFile psiFile,
@NotNull Collection<? extends JavadocParameterInfo> data,
@NotNull JavadocParameterInfo anchor) {
int descriptionStartColumn = -1;
int parameterNameEndColumn = -1;
for (JavadocParameterInfo parameterInfo : data) {
parameterNameEndColumn = Math.max(parameterNameEndColumn, parameterInfo.parameterNameEndPosition.column);
if (parameterInfo.parameterDescriptionStartPosition != null) {
descriptionStartColumn = Math.max(descriptionStartColumn, parameterInfo.parameterDescriptionStartPosition.column);
}
}
int column;
if (getJdAlignParamComments(psiFile)) {
column = Math.max(descriptionStartColumn, parameterNameEndColumn);
if (column <= parameterNameEndColumn) {
column = parameterNameEndColumn + 1;
}
}
else {
column = anchor.parameterNameEndPosition.column + 1;
}
return new LogicalPosition(anchor.parameterNameEndPosition.line, column);
}
protected abstract boolean getJdAlignParamComments(@NotNull PsiFile psiFile);
/**
* Returns information about all lines that contain javadoc parameters and are adjacent to the one that holds given offset.
*
* @param psiFile PSI holder for the document exposed the given editor
* @param editor target editor
* @param offset target offset that identifies anchor line to check
* @return pair like (javadoc info for the line identified by the given offset; list of javadoc parameter infos for
* adjacent lines if any
*/
public @NotNull Pair<JavadocParameterInfo, List<JavadocParameterInfo>> parse(@NotNull PsiFile psiFile,
@NotNull Editor editor,
int offset) {
List<JavadocParameterInfo> result = new ArrayList<>();
PsiDocumentManager.getInstance(psiFile.getProject()).commitDocument(editor.getDocument());
final PsiElement elementAtCaret = psiFile.findElementAt(offset);
if (elementAtCaret == null) {
return EMPTY;
}
ASTNode nodeAtCaret = BasicJavaAstTreeUtil.toNode(elementAtCaret);
ASTNode tag = BasicJavaAstTreeUtil.getParentOfType(nodeAtCaret, TAG_TOKEN_SET);
if (tag == null) {
// Due to javadoc PSI specifics.
if (BasicJavaAstTreeUtil.isWhiteSpace(nodeAtCaret)) {
for (ASTNode e = nodeAtCaret.getTreePrev(); e != null && tag == null; e = e.getTreePrev()) {
tag = BasicJavaAstTreeUtil.getParentOfType(e, TAG_TOKEN_SET, false);
if (e instanceof PsiWhiteSpace
|| (e.getElementType() == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS)) {
continue;
}
break;
}
}
}
if (tag == null) {
return EMPTY;
}
JavadocParameterInfo anchorInfo = parse(tag, editor);
if (anchorInfo == null) {
return EMPTY;
}
// Parse previous parameters.
for (ASTNode n = tag.getTreePrev(); n != null; n = n.getTreePrev()) {
JavadocParameterInfo info = parse(n, editor);
if (info == null) {
break;
}
result.add(0, info);
}
result.add(anchorInfo);
// Parse subsequent parameters.
for (ASTNode n = tag.getTreeNext(); n != null; n = n.getTreeNext()) {
JavadocParameterInfo info = parse(n, editor);
if (info == null) {
break;
}
result.add(info);
}
return Pair.create(anchorInfo, result);
}
private static @Nullable JavadocParameterInfo parse(@NotNull ASTNode astNode, @NotNull Editor editor) {
final ASTNode tag = BasicJavaAstTreeUtil.getParentOfType(astNode, TAG_TOKEN_SET, false);
if (tag == null || !PARAM_TEXT.equals(BasicJavaAstTreeUtil.getTagName(tag))) {
return null;
}
final ASTNode paramRef = BasicJavaAstTreeUtil.findChildByType(tag, BASIC_DOC_TAG_VALUE_ELEMENT,
BASIC_DOC_METHOD_OR_FIELD_REF,
BASIC_DOC_PARAMETER_REF,
BASIC_DOC_SNIPPET_TAG_VALUE);
if (paramRef == null) {
return null;
}
for (ASTNode node = paramRef.getTreeNext(); node != null; node = node.getTreeNext()) {
final IElementType elementType = node.getElementType();
if (elementType == JavaDocTokenType.DOC_COMMENT_DATA) {
return new JavadocParameterInfo(
editor.offsetToLogicalPosition(paramRef.getTextRange().getEndOffset()),
editor.offsetToLogicalPosition(node.getTextRange().getStartOffset()),
editor.getDocument().getLineNumber(node.getTextRange().getEndOffset())
);
}
else if (elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) {
break;
}
}
return new JavadocParameterInfo(
editor.offsetToLogicalPosition(paramRef.getTextRange().getEndOffset()),
null,
editor.getDocument().getLineNumber(paramRef.getTextRange().getEndOffset())
);
}
/**
* Encapsulates information about source code line that holds javadoc parameter.
*/
public static class JavadocParameterInfo {
/**
* Logical position that points to location just after javadoc parameter name.
* <p/>
* Example:
* <pre>
* /**
* * @param i[X] description
* *&#47;
* </pre>
*/
public final @NotNull LogicalPosition parameterNameEndPosition;
public final @Nullable LogicalPosition parameterDescriptionStartPosition;
/** Last logical line occupied by the current javadoc parameter. */
public final int lastLine;
public JavadocParameterInfo(@NotNull LogicalPosition parameterNameEndPosition,
@Nullable LogicalPosition parameterDescriptionStartPosition,
int lastLine) {
this.parameterNameEndPosition = parameterNameEndPosition;
this.parameterDescriptionStartPosition = parameterDescriptionStartPosition;
this.lastLine = lastLine;
}
@Override
public String toString() {
return "name end: " + parameterNameEndPosition + ", description start: " + parameterDescriptionStartPosition;
}
}
}
@@ -16,24 +16,236 @@
package com.intellij.javadoc;
import com.intellij.application.options.CodeStyle;
import com.intellij.psi.PsiFile;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.impl.source.BasicJavaAstTreeUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.ParentAwareTokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.intellij.psi.impl.source.BasicJavaDocElementType.*;
/**
* This class is not singleton but provides {@link #getInstance() single-point-of-usage field}.
* Utility methods to support some Javadoc-related operations like formatting or navigation
*/
public final class JavadocHelper extends AbstractBasicJavadocHelper {
private static final JavadocHelper INSTANCE = new JavadocHelper();
public final class JavadocHelper {
private static final Pair<JavadocParameterInfo, List<JavadocParameterInfo>> EMPTY
= new Pair<>(null, Collections.emptyList());
private static final String PARAM_TEXT = "param";
private static final @NotNull ParentAwareTokenSet TAG_TOKEN_SET =
ParentAwareTokenSet.create(BASIC_DOC_TAG, BASIC_DOC_SNIPPET_TAG, BASIC_DOC_INLINE_TAG);
@Override
protected boolean getJdAlignParamComments(@NotNull PsiFile psiFile) {
private JavadocHelper() {
}
private static boolean getJdAlignParamComments(@NotNull PsiFile psiFile) {
final CodeStyleSettings codeStyleSettings = CodeStyle.getSettings(psiFile);
return (codeStyleSettings.getCustomSettings(JavaCodeStyleSettings.class).JD_ALIGN_PARAM_COMMENTS);
}
public static @NotNull JavadocHelper getInstance() {
return INSTANCE;
/**
* Tries to navigate caret at the given editor to the target position, inserting missing white spaces if necessary.
*
* @param position target caret position
* @param editor target editor
* @param project target project
*/
public static void navigate(@NotNull LogicalPosition position, @NotNull Editor editor, final @NotNull Project project) {
final Document document = editor.getDocument();
final CaretModel caretModel = editor.getCaretModel();
final int endLineOffset = document.getLineEndOffset(position.line);
final LogicalPosition endLinePosition = editor.offsetToLogicalPosition(endLineOffset);
if (endLinePosition.column < position.column && !editor.getSettings().isVirtualSpace() && !editor.isViewer()) {
final String toInsert = StringUtil.repeat(" ", position.column - endLinePosition.column);
ApplicationManager.getApplication().runWriteAction(() -> {
document.insertString(endLineOffset, toInsert);
PsiDocumentManager.getInstance(project).commitDocument(document);
});
}
caretModel.moveToLogicalPosition(position);
}
/**
* Calculates desired position of target javadoc parameter's description start.
*
* @param psiFile PSI holder
* @param data parsed adjacent javadoc parameters
* @param anchor descriptor for the target parameter
* @return logical position that points to the desired parameter description start location
*/
public static @NotNull LogicalPosition calculateDescriptionStartPosition(@NotNull PsiFile psiFile,
@NotNull Collection<? extends JavadocParameterInfo> data,
@NotNull JavadocParameterInfo anchor) {
int descriptionStartColumn = -1;
int parameterNameEndColumn = -1;
for (JavadocParameterInfo parameterInfo : data) {
parameterNameEndColumn = Math.max(parameterNameEndColumn, parameterInfo.parameterNameEndPosition.column);
if (parameterInfo.parameterDescriptionStartPosition != null) {
descriptionStartColumn = Math.max(descriptionStartColumn, parameterInfo.parameterDescriptionStartPosition.column);
}
}
int column;
if (getJdAlignParamComments(psiFile)) {
column = Math.max(descriptionStartColumn, parameterNameEndColumn);
if (column <= parameterNameEndColumn) {
column = parameterNameEndColumn + 1;
}
}
else {
column = anchor.parameterNameEndPosition.column + 1;
}
return new LogicalPosition(anchor.parameterNameEndPosition.line, column);
}
/**
* Returns information about all lines that contain javadoc parameters and are adjacent to the one that holds given offset.
*
* @param psiFile PSI holder for the document exposed the given editor
* @param editor target editor
* @param offset target offset that identifies anchor line to check
* @return pair like (javadoc info for the line identified by the given offset; list of javadoc parameter infos for
* adjacent lines if any
*/
public static @NotNull Pair<JavadocParameterInfo, List<JavadocParameterInfo>> parse(@NotNull PsiFile psiFile,
@NotNull Editor editor,
int offset) {
List<JavadocParameterInfo> result = new ArrayList<>();
PsiDocumentManager.getInstance(psiFile.getProject()).commitDocument(editor.getDocument());
final PsiElement elementAtCaret = psiFile.findElementAt(offset);
if (elementAtCaret == null) {
return EMPTY;
}
ASTNode nodeAtCaret = BasicJavaAstTreeUtil.toNode(elementAtCaret);
ASTNode tag = BasicJavaAstTreeUtil.getParentOfType(nodeAtCaret, TAG_TOKEN_SET);
if (tag == null) {
// Due to javadoc PSI specifics.
if (BasicJavaAstTreeUtil.isWhiteSpace(nodeAtCaret)) {
for (ASTNode e = nodeAtCaret.getTreePrev(); e != null && tag == null; e = e.getTreePrev()) {
tag = BasicJavaAstTreeUtil.getParentOfType(e, TAG_TOKEN_SET, false);
if (e instanceof PsiWhiteSpace
|| (e.getElementType() == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS)) {
continue;
}
break;
}
}
}
if (tag == null) {
return EMPTY;
}
JavadocParameterInfo anchorInfo = parse(tag, editor);
if (anchorInfo == null) {
return EMPTY;
}
// Parse previous parameters.
for (ASTNode n = tag.getTreePrev(); n != null; n = n.getTreePrev()) {
JavadocParameterInfo info = parse(n, editor);
if (info == null) {
break;
}
result.add(0, info);
}
result.add(anchorInfo);
// Parse subsequent parameters.
for (ASTNode n = tag.getTreeNext(); n != null; n = n.getTreeNext()) {
JavadocParameterInfo info = parse(n, editor);
if (info == null) {
break;
}
result.add(info);
}
return Pair.create(anchorInfo, result);
}
private static @Nullable JavadocParameterInfo parse(@NotNull ASTNode astNode, @NotNull Editor editor) {
final ASTNode tag = BasicJavaAstTreeUtil.getParentOfType(astNode, TAG_TOKEN_SET, false);
if (tag == null || !PARAM_TEXT.equals(BasicJavaAstTreeUtil.getTagName(tag))) {
return null;
}
final ASTNode paramRef = BasicJavaAstTreeUtil.findChildByType(tag, BASIC_DOC_TAG_VALUE_ELEMENT,
BASIC_DOC_METHOD_OR_FIELD_REF,
BASIC_DOC_PARAMETER_REF,
BASIC_DOC_SNIPPET_TAG_VALUE);
if (paramRef == null) {
return null;
}
for (ASTNode node = paramRef.getTreeNext(); node != null; node = node.getTreeNext()) {
final IElementType elementType = node.getElementType();
if (elementType == JavaDocTokenType.DOC_COMMENT_DATA) {
return new JavadocParameterInfo(
editor.offsetToLogicalPosition(paramRef.getTextRange().getEndOffset()),
editor.offsetToLogicalPosition(node.getTextRange().getStartOffset()),
editor.getDocument().getLineNumber(node.getTextRange().getEndOffset())
);
}
else if (elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS) {
break;
}
}
return new JavadocParameterInfo(
editor.offsetToLogicalPosition(paramRef.getTextRange().getEndOffset()),
null,
editor.getDocument().getLineNumber(paramRef.getTextRange().getEndOffset())
);
}
/**
* Encapsulates information about source code line that holds javadoc parameter.
*/
public static class JavadocParameterInfo {
/**
* Logical position that points to location just after javadoc parameter name.
* <p/>
* Example:
* <pre>
* /**
* * @param i[X] description
* *&#47;
* </pre>
*/
public final @NotNull LogicalPosition parameterNameEndPosition;
public final @Nullable LogicalPosition parameterDescriptionStartPosition;
/** Last logical line occupied by the current javadoc parameter. */
public final int lastLine;
public JavadocParameterInfo(@NotNull LogicalPosition parameterNameEndPosition,
@Nullable LogicalPosition parameterDescriptionStartPosition,
int lastLine) {
this.parameterNameEndPosition = parameterNameEndPosition;
this.parameterDescriptionStartPosition = parameterDescriptionStartPosition;
this.lastLine = lastLine;
}
@Override
public String toString() {
return "name end: " + parameterNameEndPosition + ", description start: " + parameterDescriptionStartPosition;
}
}
}