From aba4573d3d09c316da2dcf938eaf64811222a9c5 Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Thu, 28 Jun 2018 21:53:28 +0300 Subject: [PATCH] IDEA-180882 Code formatting doesn't remove invalid/empty Javadoc tags --- ...JavaLanguageCodeStyleSettingsProvider.java | 51 +++++++++++-------- .../source/codeStyle/javadoc/JDComment.java | 17 ++++--- .../codeInsight/addJavadoc/afterMethod2.java | 2 +- .../editorActions/FixDocCommentTest.groovy | 49 +++++++++++++++++- .../psi/formatter/java/JavaFormatterTest.kt | 19 ++++++- .../formatter/java/JavadocFormatterTest.kt | 33 +++++++++++- .../psi/codeStyle/DocCommentSettings.java | 20 ++++++++ .../LanguageCodeStyleSettingsProvider.java | 9 ++-- .../editorActions/FixDocCommentAction.java | 34 +++++++------ .../codeStyle/CodeStyleManagerImpl.java | 2 +- 10 files changed, 183 insertions(+), 53 deletions(-) diff --git a/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java b/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java index 0cd05f08bfbb..2c748e65e676 100644 --- a/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java +++ b/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java @@ -15,7 +15,6 @@ */ package com.intellij.ide; -import com.intellij.application.options.CodeStyle; import com.intellij.application.options.CodeStyleBean; import com.intellij.application.options.IndentOptionsEditor; import com.intellij.application.options.JavaIndentOptionsEditor; @@ -278,29 +277,39 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett @Override @NotNull - public DocCommentSettings getDocCommentSettings(@NotNull PsiFile file) { - if (file.isValid()) { - return new DocCommentSettings() { - private final JavaCodeStyleSettings mySettings = - CodeStyle.getCustomSettings(file, JavaCodeStyleSettings.class); + public DocCommentSettings getDocCommentSettings(@NotNull CodeStyleSettings rootSettings) { + return new DocCommentSettings() { + private final JavaCodeStyleSettings mySettings = + rootSettings.getCustomSettings(JavaCodeStyleSettings.class); - @Override - public boolean isDocFormattingEnabled() { - return mySettings.ENABLE_JAVADOC_FORMATTING; - } + @Override + public boolean isDocFormattingEnabled() { + return mySettings.ENABLE_JAVADOC_FORMATTING; + } - @Override - public void setDocFormattingEnabled(boolean formattingEnabled) { - mySettings.ENABLE_JAVADOC_FORMATTING = formattingEnabled; - } + @Override + public void setDocFormattingEnabled(boolean formattingEnabled) { + mySettings.ENABLE_JAVADOC_FORMATTING = formattingEnabled; + } + + @Override + public boolean isLeadingAsteriskEnabled() { + return mySettings.JD_LEADING_ASTERISKS_ARE_ENABLED; + } + + @Override + public boolean isRemoveEmptyTags() { + return mySettings.JD_KEEP_EMPTY_EXCEPTION || mySettings.JD_KEEP_EMPTY_PARAMETER || mySettings.JD_KEEP_EMPTY_RETURN; + } + + @Override + public void setRemoveEmptyTags(boolean removeEmptyTags) { + mySettings.JD_KEEP_EMPTY_RETURN = !removeEmptyTags; + mySettings.JD_KEEP_EMPTY_PARAMETER = !removeEmptyTags; + mySettings.JD_KEEP_EMPTY_EXCEPTION = !removeEmptyTags; + } + }; - @Override - public boolean isLeadingAsteriskEnabled() { - return mySettings.JD_LEADING_ASTERISKS_ARE_ENABLED; - } - }; - } - return super.getDocCommentSettings(file); } @Nullable diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java index f91057929b24..5646a9b941d7 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java @@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.codeStyle.javadoc; import com.intellij.formatting.IndentInfo; import com.intellij.ide.highlighter.JavaFileType; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import org.jetbrains.annotations.NotNull; @@ -80,7 +81,6 @@ public class JDComment { } StringBuilder sb = new StringBuilder(); - int start = sb.length(); if (!isNull(myDescription)) { sb.append(myFormatter.getParser().formatJDTagDescription(myDescription, prefix)); @@ -126,12 +126,15 @@ public class JDComment { sb.append(tagDescription); } - if (sb.length() == start) return null; - - // if it ends with a blank line delete that - int nlen = sb.length() - prefix.length() - 1; - if (sb.substring(nlen, sb.length()).equals(prefix + "\n")) { - sb.delete(nlen, sb.length()); + if (sb.length() > prefix.length()) { + // if it ends with a blank line delete that + int nlen = sb.length() - prefix.length() - 1; + if (sb.substring(nlen, sb.length()).equals(prefix + "\n")) { + sb.delete(nlen, sb.length()); + } + } + else if (sb.length() == 0 && !StringUtil.isEmpty(myEndLine)) { + sb.append('\n').append('*').append('\n'); } if (myMultiLineComment && myFormatter.getSettings().JD_DO_NOT_WRAP_ONE_LINE_COMMENTS diff --git a/java/java-tests/testData/codeInsight/addJavadoc/afterMethod2.java b/java/java-tests/testData/codeInsight/addJavadoc/afterMethod2.java index a86a2f943c81..502b0b1b99bf 100644 --- a/java/java-tests/testData/codeInsight/addJavadoc/afterMethod2.java +++ b/java/java-tests/testData/codeInsight/addJavadoc/afterMethod2.java @@ -2,7 +2,7 @@ class A { /** - * @param s + * @param s * @return * @throws Exception */ diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/editorActions/FixDocCommentTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/editorActions/FixDocCommentTest.groovy index dc8a3ba857a4..0a81751d9583 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/editorActions/FixDocCommentTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/editorActions/FixDocCommentTest.groovy @@ -15,8 +15,11 @@ */ package com.intellij.java.codeInsight.editorActions +import com.intellij.application.options.CodeStyle import com.intellij.codeInsight.editorActions.FixDocCommentAction import com.intellij.openapi.editor.impl.AbstractEditorTest +import com.intellij.psi.codeStyle.JavaCodeStyleBean +import org.jetbrains.annotations.NotNull /** * @author Denis Zhdanov @@ -35,7 +38,7 @@ class Test { expected: '''\ class Test { /** - * @param i + * @param i * @return */ String test(int i) { @@ -584,10 +587,54 @@ class Test { ) } + void testWithEmptyTagsRemovalOption() { + codeStyleBean.with { + javaDocKeepEmptyParameter = false + javaDocKeepEmptyReturn = false + javaDocKeepEmptyException = false + } + doTest( + initial: '''package com.company; + +public class Test +{ + int foo(String s, int i, double d) throws Exception + { + return 0; + } +} +''', + expected: '''package com.company; + +public class Test +{ + /** + * @param s + * @param i + * @param d + * @return + * @throws Exception + */ + int foo(String s, int i, double d) throws Exception + { + return 0; + } +} +''' + ) + } + private def doTest(Map args) { configureFromFileText("${getTestName(false)}.java", args.initial) myEditor.settings.virtualSpace = false executeAction(FixDocCommentAction.ACTION_ID) checkResultByText(args.expected) } + + @NotNull + static JavaCodeStyleBean getCodeStyleBean() { + JavaCodeStyleBean codeStyleBean = new JavaCodeStyleBean() + codeStyleBean.setRootSettings(CodeStyle.getSettings(getProject())) + return codeStyleBean + } } diff --git a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaFormatterTest.kt b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaFormatterTest.kt index 4a95a14e0a23..178f38a9ec41 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaFormatterTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaFormatterTest.kt @@ -601,8 +601,23 @@ class JavaFormatterTest : AbstractJavaFormatterTest() { } fun testTwoJavaDocs() { - doTextTest("/**\n" + " * \n" + " */\n" + " class Test {\n" + " /**\n" + " */\n" + " public void foo();\n" + "}", - "/**\n" + " *\n" + " */\n" + "class Test {\n" + " /**\n" + " */\n" + " public void foo();\n" + "}") + doTextTest("""/** + * + */ + class Test { + /** + */ + public void foo(); +}""", + """/** + * + */ +class Test { + /** + * + */ + public void foo(); +}""") } fun testJavaDocLinksWithParameterNames() { diff --git a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavadocFormatterTest.kt b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavadocFormatterTest.kt index 67eb48964588..119d5709b0d7 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavadocFormatterTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavadocFormatterTest.kt @@ -1044,7 +1044,6 @@ String test(int aParameter, int bParameter) { "/**\n" + " *\n" + - " *\n" + " */\n" + "void check() {\n" + "}") @@ -1284,6 +1283,38 @@ public class Test { private void test2(Object a, Object b, Object c, Object d, Object e) { } } +""" + ) + } + + fun testIdea180882() { + codeStyleBean.apply { + isJavaDocKeepEmptyParameter = false; + } + doTextTest( +""" +public class Test { + + /** + * @param a + * @param b + */ + public void foo(boolean a, boolean b) { + + } +} +""", + +""" +public class Test { + + /** + * + */ + public void foo(boolean a, boolean b) { + + } +} """ ) } diff --git a/platform/core-api/src/com/intellij/psi/codeStyle/DocCommentSettings.java b/platform/core-api/src/com/intellij/psi/codeStyle/DocCommentSettings.java index 3c86b15b58bd..347c73529d81 100644 --- a/platform/core-api/src/com/intellij/psi/codeStyle/DocCommentSettings.java +++ b/platform/core-api/src/com/intellij/psi/codeStyle/DocCommentSettings.java @@ -40,6 +40,17 @@ public interface DocCommentSettings { */ boolean isLeadingAsteriskEnabled(); + /** + * @return True if at least some empty tags can to be removed. + */ + boolean isRemoveEmptyTags(); + + /** + * Force or disable empty tags removal. + * @param removeEmptyTags True if all empty tags must be removed, false if all of them must be preserved. + */ + void setRemoveEmptyTags(boolean removeEmptyTags); + final class Defaults implements DocCommentSettings { @Override @@ -55,5 +66,14 @@ public interface DocCommentSettings { public boolean isLeadingAsteriskEnabled() { return true; } + + @Override + public boolean isRemoveEmptyTags() { + return false; + } + + @Override + public void setRemoveEmptyTags(boolean removeEmptyTags) { + } } } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/LanguageCodeStyleSettingsProvider.java b/platform/lang-api/src/com/intellij/psi/codeStyle/LanguageCodeStyleSettingsProvider.java index 6eaf7e2fda89..36b631e0db0f 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/LanguageCodeStyleSettingsProvider.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/LanguageCodeStyleSettingsProvider.java @@ -274,12 +274,13 @@ public abstract class LanguageCodeStyleSettingsProvider { } /** - * Returns code documentation comment settings for the PSI file. - * @param file The file to return current document settings for. - * @return Documentation comment settings. + * Returns a wrapper around language's own code documentation comment settings from the given {@code rootSettings}. + * @param rootSettings Root code style setting to retrieve doc comment settings from. + * @return {@code DocCommentSettings} wrapper object object which allows to retrieve and modify language's own + * settings related to doc comment. The object is used then by common platform doc comment handling algorithms. */ @NotNull - public DocCommentSettings getDocCommentSettings(@NotNull PsiFile file) { + public DocCommentSettings getDocCommentSettings(@NotNull CodeStyleSettings rootSettings) { return DocCommentSettings.DEFAULTS; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java index 5d602ea6ea3f..2e32c7a1c81e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java @@ -1,6 +1,7 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInsight.editorActions; +import com.intellij.application.options.CodeStyle; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.documentation.DocCommentFixer; import com.intellij.lang.*; @@ -11,10 +12,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.editor.Caret; -import com.intellij.openapi.editor.CaretModel; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.project.Project; @@ -22,6 +20,9 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.DocCommentSettings; +import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -195,15 +196,6 @@ public class FixDocCommentAction extends EditorAction { CaretModel caretModel = editor.getCaretModel(); if (stub != null) { int insertionOffset = commentStartOffset + commentBodyRelativeOffset; - //if (CodeStyleSettingsManager.getSettings(project).JD_ADD_BLANK_AFTER_DESCRIPTION) { - // buffer.setLength(0); - // if (linePrefix != null) { - // buffer.append(linePrefix); - // } - // buffer.append("\n"); - // buffer.append(stub); - // stub = buffer.toString(); - //} document.insertString(insertionOffset, stub); docManager.commitDocument(document); pair = documentationProvider.parseContext(anchor); @@ -221,8 +213,9 @@ public class FixDocCommentAction extends EditorAction { int start = Math.min(calcStartReformatOffset(pair.first), calcStartReformatOffset(pair.second)); int end = pair.second.getTextRange().getEndOffset(); - CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); - codeStyleManager.reformatText(anchor.getContainingFile(), start, end); + int caretLine = document.getLineNumber(editor.getCaretModel().getOffset()); + reformatCommentKeepingEmptyTags(anchor.getContainingFile(), project, start, end); + editor.getCaretModel().moveToOffset(document.getLineEndOffset(caretLine)); int caretOffset = caretModel.getOffset(); if (caretOffset > 0 && caretOffset <= document.getTextLength()) { @@ -234,6 +227,17 @@ public class FixDocCommentAction extends EditorAction { } } + private static void reformatCommentKeepingEmptyTags(@NotNull PsiFile file, @NotNull Project project, int start, int end) { + CodeStyleSettings tempSettings = CodeStyle.getSettings(file).clone(); + LanguageCodeStyleSettingsProvider langProvider = LanguageCodeStyleSettingsProvider.forLanguage(file.getLanguage()); + if (langProvider != null) { + DocCommentSettings docCommentSettings = langProvider.getDocCommentSettings(tempSettings); + docCommentSettings.setRemoveEmptyTags(false); + } + CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); + CodeStyle.doWithTemporarySettings(project, tempSettings, () -> codeStyleManager.reformatText(file, start, end)); + } + private static int calcStartReformatOffset(@NotNull PsiElement element) { int result = element.getTextRange().getStartOffset(); for (PsiElement e = element.getPrevSibling(); e != null; e = e.getPrevSibling()) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java index 96c0cedc9ee7..c1663b0e2d94 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java @@ -918,7 +918,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting Language language = file.getLanguage(); LanguageCodeStyleSettingsProvider settingsProvider = LanguageCodeStyleSettingsProvider.forLanguage(language); if (settingsProvider != null) { - return settingsProvider.getDocCommentSettings(file); + return settingsProvider.getDocCommentSettings(CodeStyle.getSettings(file)); } return DocCommentSettings.DEFAULTS; }