From 698499bfb0ca553b1eacb931b8feddd548dfb93e Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Mon, 24 Sep 2012 16:50:17 +0400 Subject: [PATCH] IDEA-76469 Regenerate the javadoc All javadoc fixes except ordering --- .../documentation/JavaDocCommentFixer.java | 124 +++++++++++++---- .../editorActions/FixDocCommentTest.groovy | 129 +++++++++++++++--- 2 files changed, 211 insertions(+), 42 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java b/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java index 47e6c61183a9..69d7faf9497b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java +++ b/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java @@ -24,6 +24,8 @@ import com.intellij.javadoc.JavadocNavigationDelegate; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.javadoc.PsiDocComment; @@ -63,28 +65,15 @@ public class JavaDocCommentFixer implements DocCommentFixer { */ @NotNull private static final Set CARET_ANCHOR_TAGS = ContainerUtilRt.newHashSet(PARAM_TAG, "@throws", "@return"); - @NotNull private static final List TAGS_ORDER = new ArrayList(); - static { - String tags = System.getProperty("java.doc.comment.fix.tags.order"); - if (tags == null) { - tags = "@param:@return:@throws"; - } - - for (String s : tags.split(":")) { - String tagName = s.trim(); - if (!tagName.isEmpty()) { - TAGS_ORDER.add("@" + tagName); - } - } - } - - private static final Comparator COMPARATOR = new Comparator() { + @NotNull private static final Comparator COMPARATOR = new Comparator() { @Override public int compare(PsiElement e1, PsiElement e2) { return e2.getTextRange().getEndOffset() - e1.getTextRange().getEndOffset(); } }; + @NotNull private static final String PARAM_TAG_NAME = "param"; + @Override public void fixComment(@NotNull Project project, @NotNull Editor editor, @NotNull PsiComment comment) { if (!(comment instanceof PsiDocComment)) { @@ -96,7 +85,12 @@ public class JavaDocCommentFixer implements DocCommentFixer { if (owner == null) { return; } - + + PsiFile file = comment.getContainingFile(); + if (file == null) { + return; + } + JavaDocReferenceInspection referenceInspection = new JavaDocReferenceInspection(); JavaDocLocalInspection localInspection = getDocLocalInspection(); @@ -125,7 +119,7 @@ public class JavaDocCommentFixer implements DocCommentFixer { PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); ensureContentOrdered(docComment, editor.getDocument()); - locateCaret(docComment, editor); + locateCaret(docComment, editor, file); } @NotNull @@ -163,7 +157,16 @@ public class JavaDocCommentFixer implements DocCommentFixer { } } - // TODO den add doc + /** + * This fixer is based on existing javadoc inspections - there are two of them. One detects invalid references (to unexisted + * method parameter or non-declared checked exception). Another one handles all other cases (parameter documentation is missing; + * parameter doesn't have a description etc). This method handles result of the second exception + * + * @param problems detected problems + * @param comment target comment to fix + * @param document target document which contains text of the commen being fixed + * @param project current project + */ @SuppressWarnings("unchecked") private static void fixCommonProblems(@NotNull ProblemDescriptor[] problems, @NotNull PsiComment comment, @@ -200,8 +203,9 @@ public class JavaDocCommentFixer implements DocCommentFixer { if (toRemove.size() > 1) { Collections.sort(toRemove, COMPARATOR); } - - PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document); + + PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project); + psiDocumentManager.doPostponedOperationsAndUnblockDocument(document); CharSequence text = document.getCharsSequence(); for (PsiElement element : toRemove) { int startOffset = element.getTextRange().getStartOffset(); @@ -225,20 +229,90 @@ public class JavaDocCommentFixer implements DocCommentFixer { } document.deleteString(startOffset, endOffset); } + psiDocumentManager.commitDocument(document); } private static void ensureContentOrdered(@NotNull PsiDocComment comment, @NotNull Document document) { + //region Parse existing doc comment parameters. + List current = new ArrayList(); + Map> tagInfoByName = new HashMap>(); + for (PsiDocTag tag : comment.getTags()) { + if (!PARAM_TAG_NAME.equals(tag.getName())) { + continue; + } + PsiDocTagValue valueElement = tag.getValueElement(); + if (valueElement == null) { + continue; + } + String paramName = valueElement.getText(); + if (paramName != null) { + current.add(paramName); + tagInfoByName.put(paramName, parseTagValue(tag, document)); + } + } + //endregion + + + //region Calculate desired parameters order + List ordered = new ArrayList(); PsiDocCommentOwner owner = comment.getOwner(); if ((owner instanceof PsiMethod)) { - ensureParametersOrder(comment, (PsiMethod)owner, document); + PsiParameter[] parameters = ((PsiMethod)owner).getParameterList().getParameters(); + for (PsiParameter parameter : parameters) { + ordered.add(parameter.getName()); + } } + if (owner instanceof PsiTypeParameterListOwner) { + PsiTypeParameter[] typeParameters = ((PsiTypeParameterListOwner)owner).getTypeParameters(); + for (PsiTypeParameter parameter : typeParameters) { + ordered.add(String.format("<%s>", parameter.getName())); + } + } + //endregion + + //region Fix order if necessary. + if (current.size() != ordered.size()) { + // Something is wrong, stop the processing. + return; + } + + boolean changed = false; + for (int i = current.size() - 1; i >= 0; i--) { + String newTag = ordered.get(i); + String oldTag = current.get(i); + if (newTag.equals(oldTag)) { + continue; + } + TextRange range = tagInfoByName.get(oldTag).first; + document.replaceString(range.getStartOffset(), range.getEndOffset(), tagInfoByName.get(newTag).second); + changed = true; + } + + if (changed) { + PsiDocumentManager manager = PsiDocumentManager.getInstance(comment.getProject()); + manager.commitDocument(document); + } + //endregion } - private static void ensureParametersOrder(@NotNull PsiDocComment comment, @NotNull PsiMethod method, @NotNull Document document) { + @NotNull + private static Pair parseTagValue(@NotNull PsiDocTag tag, @NotNull Document document) { + PsiDocTagValue valueElement = tag.getValueElement(); + assert valueElement != null; + int startOffset = valueElement.getTextRange().getStartOffset(); + int endOffset = tag.getTextRange().getEndOffset(); + // Javadoc PSI is rather weird... + CharSequence text = document.getCharsSequence(); + int i = CharArrayUtil.shiftBackward(text, endOffset - 1, " \t*"); + if (i > 0 && text.charAt(i) == '\n') { + endOffset = i; + } + + return Pair.create(TextRange.create(startOffset, endOffset), text.subSequence(startOffset, endOffset).toString()); } - private static void locateCaret(@NotNull PsiDocComment comment, @NotNull Editor editor) { + private static void locateCaret(@NotNull PsiDocComment comment, @NotNull Editor editor, @NotNull PsiFile file) { Document document = editor.getDocument(); int lineToNavigate = -1; for (PsiDocTag tag : comment.getTags()) { @@ -274,7 +348,7 @@ public class JavaDocCommentFixer implements DocCommentFixer { if (lineToNavigate >= 0) { editor.getCaretModel().moveToOffset(document.getLineEndOffset(lineToNavigate)); - JavadocNavigationDelegate.navigateToLineEnd(editor, comment.getContainingFile()); + JavadocNavigationDelegate.navigateToLineEnd(editor, file); } } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/FixDocCommentTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/FixDocCommentTest.groovy index f3495c1e0438..e5ff63b43a6a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/FixDocCommentTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/FixDocCommentTest.groovy @@ -427,14 +427,15 @@ class Test { }''') } - void _testCorrectParametersOrder() { + void testCorrectParametersOrder() { doTest( initial: '''\ class Test { /** * @param j - * @param k k description - * @param i + * @param k single line description + * @param i multi-line + * description */ public void test(int i, int j, int k) { } @@ -442,9 +443,10 @@ class Test { expected: '''\ class Test { /** - * @param i - * @param j - * @param k k description + * @param i multi-line + * description + * @param j + * @param k single line description */ public void test(int i, int j, int k) { } @@ -452,12 +454,113 @@ class Test { ) } - void testCorrectTypeParametersOrder() { - // TODO den implement + void testCorrectParametersDescriptionWhenIndentIsDefines() { + doTest( + initial: '''\ +class Test { + /** + * @param j + * @param i + */ + public void test(int i, int j) { + } +}''', + expected: '''\ +class Test { + /** + * @param i + * @param j + */ + public void test(int i, int j) { + } +}''' + ) + } + + void testCorrectMethodTypeParametersOrder() { + doTest( + initial: '''\ +class Test { + /** + * @param + * @param A description + */ + void test() { + } +}''', + expected: '''\ +class Test { + /** + * @param A description + * @param + */ + void test() { + } +}''' + ) + } + + void testCorrectClassTypeParametersOrder() { + doTest( + initial: '''\ +/** + * Class description + * @author Zigmund + * @param multi-line + * description + * @param + */ +class Test { +}''', + expected: '''\ +/** + * Class description + * @author Zigmund + * @param + * @param multi-line + * description + */ +class Test { +}''' + ) } void testAllesZusammen() { - // TODO den implement + doTest( + initial: '''\ +class MyException1 extends Exception {} +class MyException2 extends Exception {} + +class Test { + /** + * Method description + * @param j j description (single line) + * @param s s description + * @param k + * k description (single line but located at another line) + * @throws MyException2 + * @return some value + */ + void test(int i, int j, int k) throws MyException1 { + } +}''', + expected: '''\ +class MyException1 extends Exception {} +class MyException2 extends Exception {} + +class Test { + /** + * Method description + * @param i + * @param j j description (single line) + * @param k + * k description (single line but located at another line) + * @throws MyException1 + */ + void test(int i, int j, int k) throws MyException1 { + } +}''' + ) } void testNavigateToMissingParamDescription() { @@ -481,14 +584,6 @@ class Test { ) } - void testNavigateToMissingReturnDescription() { - // TODO den implement - } - - void testNavigateToMissingThrowsDescription() { - // TODO den implement - } - private def doTest(Map args) { configureFromFileText("${getTestName(false)}.java", args.initial) myEditor.settings.virtualSpace = false