IDEA-180882 Code formatting doesn't remove invalid/empty Javadoc tags

This commit is contained in:
Rustam Vishnyakov
2018-06-28 22:05:58 +03:00
parent 8a18d8d712
commit aba4573d3d
10 changed files with 183 additions and 53 deletions
@@ -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
@@ -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
@@ -2,7 +2,7 @@
class A {
/**
* @param s
* @param s <caret>
* @return
* @throws Exception
*/
@@ -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 <caret>
* @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<caret>(String s, int i, double d) throws Exception
{
return 0;
}
}
''',
expected: '''package com.company;
public class Test
{
/**
* @param s <caret>
* @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
}
}
@@ -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() {
@@ -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) {
}
}
"""
)
}
@@ -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) {
}
}
}
@@ -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;
}
@@ -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()) {
@@ -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;
}