diff --git a/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java b/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java
new file mode 100644
index 000000000000..eaca9f997748
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/documentation/JavaDocCommentFixer.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.documentation;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.codeInspection.QuickFix;
+import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection;
+import com.intellij.codeInspection.javaDoc.JavaDocReferenceInspection;
+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.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.javadoc.PsiDocComment;
+import com.intellij.psi.javadoc.PsiDocTag;
+import com.intellij.psi.javadoc.PsiDocTagValue;
+import com.intellij.util.containers.ContainerUtilRt;
+import com.intellij.util.text.CharArrayUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+/**
+ * @author Denis Zhdanov
+ * @since 9/20/12 8:44 PM
+ */
+public class JavaDocCommentFixer implements DocCommentFixer {
+
+ @NotNull private static final String PARAM_TAG = "@param";
+
+ /**
+ * Lists tags eligible for moving caret to after javadoc fixing. The main idea is that we want to locate caret at the
+ * incomplete tag description after fixing the doc comment.
+ *
+ * Example:
+ *
+ * class Test {
+ * /**
+ * * Method description
+ * *
+ * * @param i 'i' argument
+ * * @param j [we want to move the caret here because j's description is missing]
+ * */
+ * void test(int i, int j) {
+ * }
+ * }
+ *
+ */
+ @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() {
+ @Override
+ public int compare(PsiElement e1, PsiElement e2) {
+ return e2.getTextRange().getEndOffset() - e1.getTextRange().getEndOffset();
+ }
+ };
+
+ @Override
+ public void fixComment(@NotNull Project project, @NotNull Editor editor, @NotNull PsiComment comment) {
+ if (!(comment instanceof PsiDocComment)) {
+ return;
+ }
+
+ PsiDocCommentOwner owner = ((PsiDocComment)comment).getOwner();
+ if (owner == null) {
+ return;
+ }
+
+ JavaDocReferenceInspection referenceInspection = new JavaDocReferenceInspection();
+ JavaDocLocalInspection localInspection = getDocLocalInspection();
+
+ InspectionManager inspectionManager = InspectionManager.getInstance(project);
+ ProblemDescriptor[] referenceProblems = null;
+ ProblemDescriptor[] otherProblems = null;
+ if (owner instanceof PsiClass) {
+ referenceProblems = referenceInspection.checkClass(((PsiClass)owner), inspectionManager, false);
+ otherProblems = localInspection.checkClass(((PsiClass)owner), inspectionManager, false);
+ }
+ else if (owner instanceof PsiField) {
+ referenceProblems = referenceInspection.checkField(((PsiField)owner), inspectionManager, false);
+ otherProblems = localInspection.checkField(((PsiField)owner), inspectionManager, false);
+ }
+ else if (owner instanceof PsiMethod) {
+ referenceProblems = referenceInspection.checkMethod((PsiMethod)owner, inspectionManager, false);
+ otherProblems = localInspection.checkMethod((PsiMethod)owner, inspectionManager, false);
+ }
+
+ if (referenceProblems != null) {
+ fixReferenceProblems(referenceProblems, project);
+ }
+ if (otherProblems != null) {
+ fixCommonProblems(otherProblems, comment, editor.getDocument(), project);
+ }
+
+ PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
+ locateCaret((PsiDocComment)comment, editor);
+ }
+
+ @NotNull
+ private static JavaDocLocalInspection getDocLocalInspection() {
+ JavaDocLocalInspection localInspection = new JavaDocLocalInspection();
+
+ //region visibility
+ localInspection.TOP_LEVEL_CLASS_OPTIONS.ACCESS_JAVADOC_REQUIRED_FOR = PsiModifier.PRIVATE;
+ localInspection.INNER_CLASS_OPTIONS.ACCESS_JAVADOC_REQUIRED_FOR = PsiModifier.PRIVATE;
+ localInspection.FIELD_OPTIONS.ACCESS_JAVADOC_REQUIRED_FOR = PsiModifier.PRIVATE;
+ localInspection.METHOD_OPTIONS.ACCESS_JAVADOC_REQUIRED_FOR = PsiModifier.PRIVATE;
+ //endregion
+
+ localInspection.IGNORE_EMPTY_DESCRIPTIONS = true;
+
+ //region class type arguments
+ if (!localInspection.TOP_LEVEL_CLASS_OPTIONS.REQUIRED_TAGS.contains(PARAM_TAG)) {
+ localInspection.TOP_LEVEL_CLASS_OPTIONS.REQUIRED_TAGS += PARAM_TAG;
+ }
+ if (!localInspection.INNER_CLASS_OPTIONS.REQUIRED_TAGS.contains(PARAM_TAG)) {
+ localInspection.INNER_CLASS_OPTIONS.REQUIRED_TAGS += PARAM_TAG;
+ }
+ //endregion
+
+ return localInspection;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void fixReferenceProblems(@NotNull ProblemDescriptor[] problems, @NotNull Project project) {
+ for (ProblemDescriptor problem : problems) {
+ QuickFix[] fixes = problem.getFixes();
+ if (fixes != null) {
+ fixes[0].applyFix(project, problem);
+ }
+ }
+ }
+
+ // TODO den add doc
+ @SuppressWarnings("unchecked")
+ private static void fixCommonProblems(@NotNull ProblemDescriptor[] problems,
+ @NotNull PsiComment comment,
+ @NotNull final Document document,
+ @NotNull Project project)
+ {
+ List toRemove = new ArrayList();
+ for (ProblemDescriptor problem : problems) {
+ PsiElement element = problem.getPsiElement();
+ if (element == null) {
+ continue;
+ }
+ if (comment.getTextRange().contains(element.getTextRange())) {
+ // Unnecessary element like '@return' at the void method's javadoc.
+ for (PsiElement e = element; e != null; e = e.getParent()) {
+ if (e instanceof PsiDocTag) {
+ toRemove.add(e);
+ break;
+ }
+ }
+ }
+ else {
+ // Problems like 'missing @param'.
+ QuickFix[] fixes = problem.getFixes();
+ if (fixes != null && fixes.length > 0) {
+ fixes[0].applyFix(project, problem);
+ }
+ }
+ }
+
+ if (toRemove.isEmpty()) {
+ return;
+ }
+ if (toRemove.size() > 1) {
+ Collections.sort(toRemove, COMPARATOR);
+ }
+
+ PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document);
+ CharSequence text = document.getCharsSequence();
+ for (PsiElement element : toRemove) {
+ int startOffset = element.getTextRange().getStartOffset();
+ int startLine = document.getLineNumber(startOffset);
+ int i = CharArrayUtil.shiftBackward(text, startOffset - 1, " \t");
+ if (i >= 0) {
+ char c = text.charAt(i);
+ if (c == '*') {
+ i = CharArrayUtil.shiftBackward(text, i - 1, " \t");
+ }
+ }
+ if (i >= 0 && text.charAt(i) == '\n') {
+ startOffset = Math.max(i, document.getLineStartOffset(startLine) - 1);
+ }
+
+ int endOffset = element.getTextRange().getEndOffset();
+ // Javadoc PSI is awkward, it includes next line text before the next tag. That's why we need to strip it.
+ i = CharArrayUtil.shiftBackward(text, endOffset - 1, " \t*");
+ if (i > 0 && text.charAt(i) == '\n') {
+ endOffset = i;
+ }
+ document.deleteString(startOffset, endOffset);
+ }
+ }
+
+ private static void locateCaret(@NotNull PsiDocComment comment, @NotNull Editor editor) {
+ Document document = editor.getDocument();
+ int lineToNavigate = -1;
+ for (PsiDocTag tag : comment.getTags()) {
+ PsiElement nameElement = tag.getNameElement();
+ if (nameElement == null || !CARET_ANCHOR_TAGS.contains(nameElement.getText())) {
+ continue;
+ }
+ boolean good = false;
+ PsiElement[] dataElements = tag.getDataElements();
+ if (dataElements != null) {
+ PsiDocTagValue valueElement = tag.getValueElement();
+ for (PsiElement element : dataElements) {
+ if (element == valueElement) {
+ continue;
+ }
+ if (!StringUtil.isEmptyOrSpaces(element.getText())) {
+ good = true;
+ break;
+ }
+ }
+ }
+ if (!good) {
+ int offset = tag.getTextRange().getEndOffset();
+ CharSequence text = document.getCharsSequence();
+ int i = CharArrayUtil.shiftBackward(text, offset - 1, " \t*");
+ if (i > 0 && text.charAt(i) == '\n') {
+ offset = i - 1;
+ }
+ lineToNavigate = document.getLineNumber(offset);
+ break;
+ }
+ }
+
+ if (lineToNavigate >= 0) {
+ editor.getCaretModel().moveToOffset(document.getLineEndOffset(lineToNavigate));
+ JavadocNavigationDelegate.navigateToLineEnd(editor, comment.getContainingFile());
+ }
+ }
+}
diff --git a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspection.java
index e9963add3b43..682268b983d5 100644
--- a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspection.java
+++ b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspection.java
@@ -92,15 +92,16 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
}
}
- @NonNls public Options TOP_LEVEL_CLASS_OPTIONS = new Options("none", "");
- @NonNls public Options INNER_CLASS_OPTIONS = new Options("none", "");
- @NonNls public Options METHOD_OPTIONS = new Options("none", "@return@param@throws or @exception");
- @NonNls public Options FIELD_OPTIONS = new Options("none", "");
- public boolean IGNORE_DEPRECATED = false;
- public boolean IGNORE_JAVADOC_PERIOD = true;
- public boolean IGNORE_DUPLICATED_THROWS = false;
- public boolean IGNORE_POINT_TO_ITSELF = false;
- public String myAdditionalJavadocTags = "";
+ @NonNls public Options TOP_LEVEL_CLASS_OPTIONS = new Options("none", "");
+ @NonNls public Options INNER_CLASS_OPTIONS = new Options("none", "");
+ @NonNls public Options METHOD_OPTIONS = new Options("none", "@return@param@throws or @exception");
+ @NonNls public Options FIELD_OPTIONS = new Options("none", "");
+ public boolean IGNORE_DEPRECATED = false;
+ public boolean IGNORE_JAVADOC_PERIOD = true;
+ public boolean IGNORE_DUPLICATED_THROWS = false;
+ public boolean IGNORE_POINT_TO_ITSELF = false;
+ public boolean IGNORE_EMPTY_DESCRIPTIONS = false;
+ public String myAdditionalJavadocTags = "";
private static final Logger LOG = Logger.getInstance("com.intellij.codeInspection.javaDoc.JavaDocLocalInspection");
@@ -145,8 +146,8 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
private class MyChangeListener implements ChangeListener {
private final JCheckBox myCheckBox;
- private final Options myOptions;
- private final String myTagName;
+ private final Options myOptions;
+ private final String myTagName;
public MyChangeListener(JCheckBox checkBox, Options options, String tagName) {
myCheckBox = checkBox;
@@ -156,7 +157,7 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
public void stateChanged(ChangeEvent e) {
if (myCheckBox.isSelected()) {
- if (!isTagRequired(myOptions,myTagName)) {
+ if (!isTagRequired(myOptions, myTagName)) {
myOptions.REQUIRED_TAGS += myTagName;
}
}
@@ -594,27 +595,29 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
}
}
- for (PsiDocTag tag : tags) {
- if ("param".equals(tag.getName())) {
- final PsiElement[] dataElements = tag.getDataElements();
- final PsiDocTagValue valueElement = tag.getValueElement();
- boolean hasProblemsWithTag = dataElements.length < 2;
- if (!hasProblemsWithTag) {
- final StringBuilder buf = new StringBuilder();
- for (PsiElement element : dataElements) {
- if (element != valueElement){
- buf.append(element.getText());
+ if (!IGNORE_EMPTY_DESCRIPTIONS) {
+ for (PsiDocTag tag : tags) {
+ if ("param".equals(tag.getName())) {
+ final PsiElement[] dataElements = tag.getDataElements();
+ final PsiDocTagValue valueElement = tag.getValueElement();
+ boolean hasProblemsWithTag = dataElements.length < 2;
+ if (!hasProblemsWithTag) {
+ final StringBuilder buf = new StringBuilder();
+ for (PsiElement element : dataElements) {
+ if (element != valueElement){
+ buf.append(element.getText());
+ }
}
+ hasProblemsWithTag = buf.toString().trim().length() == 0;
}
- hasProblemsWithTag = buf.toString().trim().length() == 0;
- }
- if (hasProblemsWithTag) {
- if (valueElement != null) {
- problems.add(createDescriptor(valueElement,
- InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", "@param " + valueElement.getText() + ""),
- manager, isOnTheFly));
+ if (hasProblemsWithTag) {
+ if (valueElement != null) {
+ problems.add(createDescriptor(valueElement,
+ InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", "@param " + valueElement.getText() + ""),
+ manager, isOnTheFly));
+ }
+
}
-
}
}
}
@@ -661,7 +664,7 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
}
}
else
- if ("return".equals(tag.getName())) {
+ if ("return".equals(tag.getName()) && !IGNORE_EMPTY_DESCRIPTIONS) {
if (extractTagDescription(tag).length() == 0) {
String message = InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", "@return");
ProblemDescriptor descriptor = manager.createProblemDescriptor(tag.getNameElement(), message, (LocalQuickFix)null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
@@ -694,10 +697,10 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
return false;
}
- private static void processThrowsTags(final PsiDocTag[] tags,
- final Map declaredExceptions,
- final InspectionManager mananger,
- @NotNull final ArrayList problems, boolean isOnTheFly) {
+ private void processThrowsTags(final PsiDocTag[] tags,
+ final Map declaredExceptions,
+ final InspectionManager mananger,
+ @NotNull final ArrayList problems, boolean isOnTheFly) {
for (PsiDocTag tag : tags) {
if ("throws".equals(tag.getName()) || "exception".equals(tag.getName())) {
final PsiDocTagValue value = tag.getValueElement();
@@ -714,7 +717,7 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
PsiClassType classType = it.next();
final PsiClass psiClass = declaredExceptions.get(classType);
if (InheritanceUtil.isInheritorOrSelf(exceptionClass, psiClass, true)) {
- if (extractThrowsTagDescription(tag).length() == 0) {
+ if (!IGNORE_EMPTY_DESCRIPTIONS && extractThrowsTagDescription(tag).length() == 0) {
problems.add(createDescriptor(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", "" + tag.getName() + ""), mananger,
isOnTheFly));
}
diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocNavigationDelegate.java b/java/java-impl/src/com/intellij/javadoc/JavadocNavigationDelegate.java
index 4a92f5bc8175..20d8005282a1 100644
--- a/java/java-impl/src/com/intellij/javadoc/JavadocNavigationDelegate.java
+++ b/java/java-impl/src/com/intellij/javadoc/JavadocNavigationDelegate.java
@@ -94,10 +94,10 @@ public class JavadocNavigationDelegate extends EditorNavigationDelegateAdapter {
return Result.CONTINUE;
}
- return navigateToLineEnd(editor, project, psiFile);
+ return navigateToLineEnd(editor, psiFile);
}
- public static Result navigateToLineEnd(@NotNull Editor editor, @NotNull Project project, @NotNull PsiFile psiFile) {
+ public static Result navigateToLineEnd(@NotNull Editor editor, @NotNull PsiFile psiFile) {
final Document document = editor.getDocument();
final CaretModel caretModel = editor.getCaretModel();
final int offset = caretModel.getOffset();
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java
index 1c104816b082..da11f11ae200 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java
@@ -272,8 +272,11 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
PsiElement lastParent,
@NotNull PsiElement place) {
assert isValid();
-
- if (processor instanceof ClassResolverProcessor && isPhysical() &&
+
+ // TODO den remove
+ boolean allowCaching = true;
+
+ if (allowCaching && processor instanceof ClassResolverProcessor && isPhysical() &&
(getUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING) == Boolean.TRUE || myResolveCache.hasUpToDateValue())) {
final ClassResolverProcessor hint = (ClassResolverProcessor)processor;
String name = hint.getName(state);
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 ef0a53746c16..f3495c1e0438 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/FixDocCommentTest.groovy
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/FixDocCommentTest.groovy
@@ -80,9 +80,418 @@ class Test {
}'''
)
}
+
+ void testRemoveOneParameterFromMany() {
+ doTest(
+ initial: '''\
+class Test {
+ /**
+ * @param i
+ * @param j
+ * @param k
+ */
+ void test(int i, int j) {
+ }
+}''',
+ expected: '''\
+class Test {
+ /**
+ * @param i
+ * @param j
+ */
+ void test(int i, int j) {
+ }
+}'''
+ )
+ }
+
+ void testRemoveTheOnlyParameter() {
+ doTest(
+ initial: '''\
+class Test {
+ /**
+ * My description
+ * @param i
+ */
+ void test() {
+ }
+}''',
+ expected: '''\
+class Test {
+ /**
+ * My description
+ */
+ void test() {
+ }
+}'''
+ )
+ }
+
+ void testRemoveReturn() {
+ doTest(
+ initial: '''\
+class Test {
+ /**
+ * My description
+ * @return data
+ */
+ void test() {
+ }
+}''',
+ expected: '''\
+class Test {
+ /**
+ * My description
+ */
+ void test() {
+ }
+}'''
+ )
+ }
+
+ void testRemoveOneThrowsFromMany() {
+ doTest(
+ initial: '''\
+class MyException1 extends Exception {}
+class MyException2 extends Exception {}
+
+class Test {
+ /**
+ * @param i my arg
+ * @throws MyException1 text1
+ * @throws MyException2 text2
+ */
+ void test(int i) throws MyException2 {
+ }
+}''',
+ expected: '''\
+class MyException1 extends Exception {}
+class MyException2 extends Exception {}
+
+class Test {
+ /**
+ * @param i my arg
+ * @throws MyException2 text2
+ */
+ void test(int i) throws MyException2 {
+ }
+}'''
+ )
+ }
+
+ void testRemoveTheOnlyThrows() {
+ doTest(
+ initial: '''\
+class MyException extends Exception {}
+
+class Test {
+ /**
+ * @param i my arg
+ * @throws MyException text
+ */
+ void test(int i) {
+ }
+}''',
+ expected: '''\
+class MyException extends Exception {}
+
+class Test {
+ /**
+ * @param i my arg
+ */
+ void test(int i) {
+ }
+}'''
+ )
+ }
+
+ void testRemoveOneTypeParameterFromMany() {
+ doTest(
+ initial: '''\
+/**
+ * @param tDescription
+ * @param vDescription
+ */
+class Test {
+}''',
+ expected: '''\
+/**
+ * @param vDescription
+ */
+class Test {
+}'''
+ )
+ }
+
+ void testRemoveMultipleTypeParameter() {
+ doTest(
+ initial: '''\
+/**
+ * @param tDescription
+ * @param vDescription
+ */
+class Test {
+}''',
+ expected: '''\
+/**
+ */
+class Test {
+}'''
+ )
+ }
+
+ void testAddFirstParameter() {
+ doTest(
+ initial: '''\
+class Test {
+ /**
+ */
+ void test(int i) {
+ }
+}''',
+ expected: '''\
+class Test {
+ /**
+ * @param i
+ */
+ void test(int i) {
+ }
+}'''
+ )
+ }
+
+ void testAddMultipleParameter() {
+ doTest(
+ initial: '''\
+class Test {
+ /**
+ * @param i
+ */
+ void test(int i, int j, int k) {
+ }
+}''',
+ expected: '''\
+class Test {
+ /**
+ * @param i
+ * @param j
+ * @param k
+ */
+ void test(int i, int j, int k) {
+ }
+}'''
+ )
+ }
+
+ void testAddReturn() {
+ doTest(
+ initial: '''\
+class Test {
+ /**
+ */
+ int test() {
+ }
+}''',
+ expected: '''\
+class Test {
+ /**
+ * @return
+ */
+ int test() {
+ }
+}'''
+ )
+ }
+
+ void testAddFirstThrows() {
+ doTest(
+ initial: '''\
+class MyException extends Exception {}
+
+class Test {
+ /**
+ * @param i my arg
+ */
+ void test(int i) throws MyException {
+ }
+}''',
+ expected: '''\
+class MyException extends Exception {}
+
+class Test {
+ /**
+ * @param i my arg
+ * @throws MyException
+ */
+ void test(int i) throws MyException {
+ }
+}''')
+ }
+
+ void testAddNonFirstThrows() {
+ doTest(
+ initial: '''\
+class MyException1 extends Exception {}
+class MyException2 extends Exception {}
+class MyException3 extends Exception {}
+
+class Test {
+ /**
+ * @param i my arg
+ * @throws MyException1
+ */
+ void test(int i) throws MyException1, MyException2, MyException3 {
+ }
+}''',
+ expected: '''\
+class MyException1 extends Exception {}
+class MyException2 extends Exception {}
+class MyException3 extends Exception {}
+
+class Test {
+ /**
+ * @param i my arg
+ * @throws MyException1
+ * @throws MyException2
+ * @throws MyException3
+ */
+ void test(int i) throws MyException1, MyException2, MyException3 {
+ }
+}''')
+ }
+
+ void testAddFirstThrowsWhenEmptyReturnIsAvailable() {
+ doTest(
+ initial: '''\
+class MyException extends Exception {}
+
+class Test {
+ /**
+ * @return
+ */
+ int test() throws MyException {
+ return 1;
+ }
+}''',
+ expected: '''\
+class MyException extends Exception {}
+
+class Test {
+ /**
+ * @return
+ * @throws MyException
+ */
+ int test() throws MyException {
+ return 1;
+ }
+}''')
+ }
+ void testAddFirstTypeParameter() {
+ doTest(
+ initial: '''\
+/**
+ * My description
+ * @author me
+ */
+class Test {
+}''',
+ expected: '''\
+/**
+ * My description
+ * @author me
+ * @param
+ */
+class Test {
+}''')
+ }
+
+ void testAddNonFirstTypeParameter() {
+ doTest(
+ initial: '''\
+/**
+ * My description
+ * @author me
+ * @param type description
+ */
+class Test {
+}''',
+ expected: '''\
+/**
+ * My description
+ * @author me
+ * @param type description
+ * @param
+ */
+class Test {
+}''')
+ }
+
+ void _testCorrectParametersOrder() {
+ doTest(
+ initial: '''\
+class Test {
+ /**
+ * @param j
+ * @param k k description
+ * @param i
+ */
+ public void test(int i, int j, int k) {
+ }
+}''',
+ expected: '''\
+class Test {
+ /**
+ * @param i
+ * @param j
+ * @param k k description
+ */
+ public void test(int i, int j, int k) {
+ }
+}'''
+ )
+ }
+
+ void testCorrectTypeParametersOrder() {
+ // TODO den implement
+ }
+
+ void testAllesZusammen() {
+ // TODO den implement
+ }
+
+ void testNavigateToMissingParamDescription() {
+ doTest(
+ initial: '''\
+class Test {
+ /**
+ * @param i
+ */
+ void test(int i) {
+ }
+}''',
+ expected: '''\
+class Test {
+ /**
+ * @param i
+ */
+ void test(int i) {
+ }
+}'''
+ )
+ }
+
+ 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
executeAction(FixDocCommentAction.ACTION_ID)
checkResultByText(args.expected)
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocCommentFixer.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocCommentFixer.java
new file mode 100644
index 000000000000..923f6adfc5e0
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocCommentFixer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.documentation;
+
+import com.intellij.lang.LanguageExtension;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiComment;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Denis Zhdanov
+ * @since 9/20/12 8:37 PM
+ */
+public interface DocCommentFixer {
+
+ LanguageExtension EXTENSION = new LanguageExtension("com.intellij.lang.documentationFixer");
+
+ // TODO den add doc
+ void fixComment(@NotNull Project project, @NotNull Editor editor, @NotNull PsiComment comment);
+}
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 353ea0cbe38a..cb3de1cb6270 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInsight.editorActions;
+import com.intellij.codeInsight.documentation.DocCommentFixer;
import com.intellij.lang.*;
import com.intellij.lang.documentation.CodeDocumentationProvider;
import com.intellij.lang.documentation.CompositeDocumentationProvider;
@@ -104,20 +105,33 @@ public class FixDocCommentAction extends EditorAction {
return;
}
final CodeDocumentationAwareCommenter commenter = (CodeDocumentationAwareCommenter)c;
+ final Runnable task;
+ if (pair.second == null || pair.second.getTextRange().isEmpty()) {
+ task = new Runnable() {
+ @Override
+ public void run() {
+ generateComment(pair.first, editor, docProvider, commenter, project);
+ }
+ };
+ }
+ else {
+ final DocCommentFixer fixer = DocCommentFixer.EXTENSION.forLanguage(language);
+ if (fixer == null) {
+ return;
+ }
+ else {
+ task = new Runnable() {
+ @Override
+ public void run() {
+ fixer.fixComment(project, editor, pair.second);
+ }
+ };
+ }
+ }
final Runnable command = new Runnable() {
@Override
public void run() {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- if (pair.second == null || pair.second.getTextRange().isEmpty()) {
- generateComment(pair.first, editor, docProvider, commenter, project);
- }
- else {
- fixCommentIfNecessary(pair.second);
- }
- }
- });
+ ApplicationManager.getApplication().runWriteAction(task);
}
};
CommandProcessor.getInstance().executeCommand(project, command, "Fix documentation", null);
@@ -246,8 +260,4 @@ public class FixDocCommentAction extends EditorAction {
}
return result;
}
-
- private static void fixCommentIfNecessary(@NotNull PsiComment docComment) {
- // TODO den implement
- }
}
diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
index 10bb417a1494..937ea57a09fd 100644
--- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
+++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
@@ -472,6 +472,8 @@
+
+
diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml
index 93c161b20774..94e5f7dd7ebc 100644
--- a/resources/src/META-INF/IdeaPlugin.xml
+++ b/resources/src/META-INF/IdeaPlugin.xml
@@ -791,6 +791,7 @@
+