diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java index 5c80f43240d7..de9cd1036298 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java @@ -16,9 +16,11 @@ package com.intellij.psi.impl.source.codeStyle; import com.intellij.lang.ASTNode; -import com.intellij.lang.StdLanguages; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; @@ -31,57 +33,51 @@ public class FormatCommentsProcessor implements PreFormatProcessor { @NotNull @Override public TextRange process(@NotNull final ASTNode element, @NotNull final TextRange range) { - final Project project = SourceTreeToPsiMap.treeElementToPsi(element).getProject(); + PsiElement e = SourceTreeToPsiMap.treeElementToPsi(element); + assert e != null; + final Project project = e.getProject(); if (!CodeStyleSettingsManager.getSettings(project).ENABLE_JAVADOC_FORMATTING || - element.getPsi().getContainingFile().getLanguage() != StdLanguages.JAVA) { + element.getPsi().getContainingFile().getLanguage() != JavaLanguage.INSTANCE) + { return range; } - return formatCommentsInner(project, element, range); } - private static TextRange formatCommentsInner(Project project, ASTNode element, final TextRange range) { - TextRange result = range; + /** + * Formats PsiDocComments of current ASTNode element and all his children PsiDocComments + */ + @NotNull + private static TextRange formatCommentsInner(@NotNull Project project, @NotNull ASTNode element, @NotNull final TextRange markedRange) { + TextRange resultTextRange = markedRange; + boolean shouldFormat = markedRange.contains(element.getTextRange()); + if (shouldFormat) { + TextRange before = element.getTextRange(); + new CommentFormatter(project).processComment(element); + int deltaRange = element.getTextRange().getLength() - before.getLength(); + resultTextRange = new TextRange(markedRange.getStartOffset(), markedRange.getEndOffset() + deltaRange); + } - // check for RepositoryTreeElement is optimization - if (shouldProcess(element)) { - final TextRange elementRange = element.getTextRange(); - - if (range.contains(elementRange)) { - new CommentFormatter(project).process(element); - final TextRange newRange = element.getTextRange(); - result = new TextRange(range.getStartOffset(), range.getEndOffset() + newRange.getLength() - elementRange.getLength()); - } - - // optimization, does not seek PsiDocComment inside fields / methods or out of range - if (element.getPsi() instanceof PsiField || - element.getPsi() instanceof PsiMethod || - element instanceof PsiDocComment || - range.getEndOffset() < elementRange.getStartOffset() - ) { - return result; - } + final PsiElement elementPsi = element.getPsi(); + // 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) { - // we expand the chameleons here for effectiveness - current.getFirstChildNode(); - result = formatCommentsInner(project, current, result); + //When element is PsiClass his 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 result; - } - private static boolean shouldProcess(final ASTNode element) { - if (element instanceof PsiDocComment) { - return true; - } - else { - return true;//element.getElementType() instanceof JavaStubElementType && - //(element.getPsi()) instanceof PsiDocCommentOwner; - } + return resultTextRange; } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/CommentFormatter.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/CommentFormatter.java index 983e67e3e03f..624c5370c4ad 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/CommentFormatter.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/CommentFormatter.java @@ -43,7 +43,7 @@ public class CommentFormatter { private final JDParser myParser; private final Project myProject; - public CommentFormatter(Project project) { + public CommentFormatter(@NotNull Project project) { mySettings = CodeStyleSettingsManager.getSettings(project); myParser = new JDParser(mySettings); myProject = project; @@ -57,7 +57,7 @@ public class CommentFormatter { return myParser; } - public void process(ASTNode element) { + public void processComment(@Nullable ASTNode element) { if (!getSettings().ENABLE_JAVADOC_FORMATTING) return; PsiElement psiElement = SourceTreeToPsiMap.treeElementToPsi(element); diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java index c50436b3df92..695ac719529d 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java @@ -320,18 +320,20 @@ public class JavaFormatterTest extends AbstractJavaFormatterTest { } public void testClassComment() throws Exception { - doTextTest("/**\n" + - "* @author smbd\n" + - "* @param some param\n" + - "* @since 1.9\n" + - "*/\n" + - "class Test{}", - "/**\n" + - " * @param some param\n" + - " * @author smbd\n" + - " * @since 1.9\n" + - " */\n" + - "class Test {\n}"); + String before = "/**\n" + + "* @author smbd\n" + + "* @param some param\n" + + "* @since 1.9\n" + + "*/\n" + + "class Test{}"; + String after = "/**\n" + + " * @param some param\n" + + " * @author smbd\n" + + " * @since 1.9\n" + + " */\n" + + "class Test {\n" + + "}"; + doTextTest(before,after); } public void testStringBinaryOperation() throws Exception { @@ -1166,23 +1168,27 @@ public class JavaFormatterTest extends AbstractJavaFormatterTest { } public void testNewLineAfterJavaDocs() throws Exception { - doTextTest("/** @noinspection InstanceVariableNamingConvention*/class Foo{\n" + - "/** @noinspection InstanceVariableNamingConvention*/int myFoo;\n" + -"/** @noinspection InstanceVariableNamingConvention*/ void foo(){}}", "/**\n" + - " * @noinspection InstanceVariableNamingConvention\n" + - " */\n" + - "class Foo {\n" + - " /**\n" + - " * @noinspection InstanceVariableNamingConvention\n" + - " */\n" + - " int myFoo;\n" + - "\n" + - " /**\n" + - " * @noinspection InstanceVariableNamingConvention\n" + - " */\n" + - " void foo() {\n" + - " }\n" + - "}"); + String before = "/** @noinspection InstanceVariableNamingConvention*/class Foo{\n" + + "/** @noinspection InstanceVariableNamingConvention*/int myFoo;\n" + + "/** @noinspection InstanceVariableNamingConvention*/ void foo(){}}"; + + String after = "/**\n" + + " * @noinspection InstanceVariableNamingConvention\n" + + " */\n" + + "class Foo {\n" + + " /**\n" + + " * @noinspection InstanceVariableNamingConvention\n" + + " */\n" + + " int myFoo;\n" + + "\n" + + " /**\n" + + " * @noinspection InstanceVariableNamingConvention\n" + + " */\n" + + " void foo() {\n" + + " }\n" + + "}"; + + doTextTest(before, after); } public void testArrayInitializerWrapping() throws Exception { diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavadocFormatterTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavadocFormatterTest.java index 5d0a54c98e99..97fa3d2c30ec 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavadocFormatterTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavadocFormatterTest.java @@ -41,6 +41,23 @@ public class JavadocFormatterTest extends AbstractJavaFormatterTest { } + public void testOneLineCommentWrappedByRightMarginIntoMultiLine() throws Exception { + getSettings().getRootSettings().WRAP_COMMENTS = true; + getSettings().getRootSettings().ENABLE_JAVADOC_FORMATTING = true; + getSettings().getRootSettings().JD_DO_NOT_WRAP_ONE_LINE_COMMENTS = true; + getSettings().getRootSettings().RIGHT_MARGIN = 35; + doTextTest( + "/** Here is one-line java-doc comment */" + + "class Foo {\n" + + "}", + "/**\n" + + " * Here is one-line java-doc\n" + + " * comment\n" + + " */\n" + + "class Foo {\n" + + "}"); + } + public void testLineFeedsArePreservedDuringWrap() { // Inspired by IDEA-61895 getSettings().getRootSettings().WRAP_COMMENTS = true; @@ -587,6 +604,5 @@ public class JavadocFormatterTest extends AbstractJavaFormatterTest { "}"; doTextTest(before, after); - } -} +} \ No newline at end of file