diff --git a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java index 0489b789379e..af43233a8b43 100644 --- a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -143,40 +143,66 @@ public class JavaDocInfoGenerator { } interface DocTagLocator { - T find(PsiDocComment comment); + T find(PsiDocCommentOwner owner, PsiDocComment comment); } - private static DocTagLocator parameterLocator(final String name) { + private static DocTagLocator parameterLocator(final int parameterIndex) { return new DocTagLocator() { @Override - public PsiDocTag find(PsiDocComment comment) { - if (comment == null) { - return null; - } + public PsiDocTag find(PsiDocCommentOwner owner, PsiDocComment comment) { + if (parameterIndex < 0 || comment == null || !(owner instanceof PsiMethod)) return null; - PsiDocTag[] tags = comment.findTagsByName("param"); - - for (PsiDocTag tag : tags) { - PsiDocTagValue value = tag.getValueElement(); - - if (value != null) { - String text = value.getText(); - - if (text != null && text.equals(name)) { - return tag; - } - } - } - - return null; + PsiParameter[] parameters = ((PsiMethod)owner).getParameterList().getParameters(); + if (parameterIndex >= parameters.length) return null; + + String name = parameters[parameterIndex].getName(); + return getParamTagByName(comment, name); } }; } + private static DocTagLocator typeParameterLocator(final int parameterIndex) { + return new DocTagLocator() { + @Override + public PsiDocTag find(PsiDocCommentOwner owner, PsiDocComment comment) { + if (parameterIndex < 0 || comment == null || !(owner instanceof PsiTypeParameterListOwner)) return null; + + PsiTypeParameter[] parameters = ((PsiTypeParameterListOwner)owner).getTypeParameters(); + if (parameterIndex >= parameters.length) return null; + + String rawName = parameters[parameterIndex].getName(); + if (rawName == null) return null; + String name = "<" + rawName + ">"; + return getParamTagByName(comment, name); + } + }; + } + + private static PsiDocTag getParamTagByName(@NotNull PsiDocComment comment, String name) { + PsiDocTag[] tags = comment.findTagsByName("param"); + return getTagByName(tags, name); + } + + private static PsiDocTag getTagByName(@NotNull PsiDocTag[] tags, String name) { + for (PsiDocTag tag : tags) { + PsiDocTagValue value = tag.getValueElement(); + + if (value != null) { + String text = value.getText(); + + if (text != null && text.equals(name)) { + return tag; + } + } + } + + return null; + } + private static DocTagLocator exceptionLocator(final String name) { return new DocTagLocator() { @Override - public PsiDocTag find(PsiDocComment comment) { + public PsiDocTag find(PsiDocCommentOwner owner, PsiDocComment comment) { if (comment == null) { return null; } @@ -467,23 +493,24 @@ public class JavaDocInfoGenerator { } private void generateTypeParametersSection(final StringBuilder buffer, final PsiClass aClass) { - final LinkedList>> result = - new LinkedList>>(); + final LinkedList result = new LinkedList(); final PsiTypeParameter[] typeParameters = aClass.getTypeParameters(); - for (PsiTypeParameter typeParameter : typeParameters) { - final DocTagLocator locator = parameterLocator("<" + typeParameter.getName() + ">"); + for (int i = 0; i < typeParameters.length; i++) { + PsiTypeParameter typeParameter = typeParameters[i]; + String name = "<" + typeParameter.getName() + ">"; + final DocTagLocator locator = typeParameterLocator(i); final Pair> inClassComment = findInClassComment(aClass, locator); if (inClassComment != null) { - result.add(inClassComment); + result.add(new ParamInfo(name, inClassComment)); } else { final Pair> pair = findInHierarchy(aClass, locator); if (pair != null) { - result.add(pair); + result.add(new ParamInfo(name, pair)); } } } - generateTypeParametersSection(buffer, result); + generateParametersSection(buffer, CodeInsightBundle.message("javadoc.type.parameters"), result); } @Nullable @@ -500,7 +527,7 @@ public class JavaDocInfoGenerator { } private static Pair> findInClassComment(final PsiClass psiClass, final DocTagLocator locator) { - final PsiDocTag tag = locator.find(getDocComment(psiClass)); + final PsiDocTag tag = locator.find(psiClass, getDocComment(psiClass)); if (tag != null) { return new Pair>(tag, new InheritDocProvider() { @Override @@ -541,17 +568,7 @@ public class JavaDocInfoGenerator { if (generatePrologueAndEpilogue) generatePrologue(buffer); - PsiClass parentClass = field.getContainingClass(); - if (parentClass != null) { - String qName = parentClass.getQualifiedName(); - if (qName != null) { - buffer.append(""); - //buffer.append(qName); - generateLink(buffer, qName, qName, field, false); - buffer.append(""); - //buffer.append("
"); - } - } + generateLinkToParentIfNeeded(buffer, field); buffer.append("
");
     generateFieldSignature(buffer, field, true);
@@ -929,8 +946,11 @@ public class JavaDocInfoGenerator {
   }
 
   private void generateMethodParameterJavaDoc(@NonNls StringBuilder buffer, PsiParameter parameter, boolean generatePrologueAndEpilogue) {
-    if (generatePrologueAndEpilogue)
+    String parameterName = parameter.getName();
+    
+    if (generatePrologueAndEpilogue) {
       generatePrologue(buffer);
+    }
 
     buffer.append("
");
     String modifiers = PsiFormatUtil.formatModifiers(parameter, PsiFormatUtilBase.JAVADOC_MODIFIERS_ONLY);
@@ -942,7 +962,7 @@ public class JavaDocInfoGenerator {
     generateType(buffer, parameter.getType(), parameter);
     buffer.append(" ");
     buffer.append("");
-    buffer.append(parameter.getName());
+    buffer.append(parameterName);
     appendInitializer(buffer, parameter);
     buffer.append("");
     buffer.append("
"); @@ -950,14 +970,14 @@ public class JavaDocInfoGenerator { final PsiElement method = PsiTreeUtil.getParentOfType(parameter, PsiMethod.class, PsiLambdaExpression.class); if (method instanceof PsiMethod) { - final PsiDocComment docComment = getDocComment((PsiMethod)method); + PsiMethod psiMethod = (PsiMethod)method; + final PsiDocComment docComment = getDocComment(psiMethod); final PsiDocTag[] localTags = docComment != null ? docComment.getTags() : PsiDocTag.EMPTY_ARRAY; - final Pair> tagInfoProvider = - findDocTag(localTags, parameter.getName(), (PsiMethod)method); + int parameterIndex = psiMethod.getParameterList().getParameterIndex(parameter); + final ParamInfo tagInfoProvider = findDocTag(localTags, parameterName, psiMethod, parameterLocator(parameterIndex)); if (tagInfoProvider != null) { - PsiElement[] elements = tagInfoProvider.first.getDataElements(); - if (elements.length != 0) generateOneParameter(elements, buffer, tagInfoProvider); + generateOneParameter(buffer, tagInfoProvider); } } @@ -969,17 +989,7 @@ public class JavaDocInfoGenerator { if (generatePrologueAndEpilogue) generatePrologue(buffer); - PsiClass parentClass = method.getContainingClass(); - if (parentClass != null) { - String qName = parentClass.getQualifiedName(); - if (qName != null) { - buffer.append(""); - generateLink(buffer, qName, qName, method, false); - //buffer.append(qName); - buffer.append(""); - //buffer.append("
"); - } - } + generateLinkToParentIfNeeded(buffer, method); buffer.append("
");
     generateMethodSignature(buffer, method, true, false);
@@ -999,7 +1009,7 @@ public class JavaDocInfoGenerator {
     }
 
     generateParametersSection(buffer, method, comment);
-    generateTypeParametersSection(buffer, method);
+    generateTypeParametersSection(buffer, method, comment);
     generateReturnsSection(buffer, method, comment);
     generateThrowsSection(buffer, method, comment);
 
@@ -1013,6 +1023,18 @@ public class JavaDocInfoGenerator {
       generateEpilogue(buffer);
   }
 
+  private static void generateLinkToParentIfNeeded(StringBuilder buffer, PsiMember member) {
+    PsiClass parentClass = member.getContainingClass();
+    if (parentClass != null) {
+      String qName = parentClass.getQualifiedName();
+      if (qName != null) {
+        buffer.append("");
+        generateLink(buffer, qName, qName, member, false);
+        buffer.append("");
+      }
+    }
+  }
+
   private static void generateMethodSignature(StringBuilder buffer, PsiMethod method, boolean generateLink, boolean useShortNames) {
     generateAnnotations(buffer, method, generateLink, true, useShortNames);
     String modifiers = PsiFormatUtil.formatModifiers(method, PsiFormatUtilBase.JAVADOC_MODIFIERS_ONLY);
@@ -1218,7 +1240,7 @@ public class JavaDocInfoGenerator {
   private void generateMethodDescription(@NonNls StringBuilder buffer, final PsiMethod method, final PsiDocComment comment) {
     final DocTagLocator descriptionLocator = new DocTagLocator() {
       @Override
-      public PsiElement[] find(PsiDocComment comment) {
+      public PsiElement[] find(PsiDocCommentOwner owner, PsiDocComment comment) {
         if (comment == null) {
           return null;
         }
@@ -1537,113 +1559,86 @@ public class JavaDocInfoGenerator {
     PsiParameter[] params = method.getParameterList().getParameters();
     PsiDocTag[] localTags = comment != null ? comment.findTagsByName("param") : PsiDocTag.EMPTY_ARRAY;
 
-    LinkedList>> collectedTags =
-      new LinkedList>>();
+    LinkedList collectedTags = new LinkedList();
 
-    for (PsiParameter param : params) {
+    for (int i = 0; i < params.length; i++) {
+      PsiParameter param = params[i];
       final String paramName = param.getName();
-      Pair> parmTag = findDocTag(localTags, paramName, method);
+      DocTagLocator tagLocator = parameterLocator(i);
+      ParamInfo parmTag = findDocTag(localTags, paramName, method, tagLocator);
 
       if (parmTag != null) {
         collectedTags.addLast(parmTag);
       }
     }
 
-    if (!collectedTags.isEmpty()) {
-      buffer.append("
"); - buffer.append("
").append(CodeInsightBundle.message("javadoc.parameters")).append(""); - for (Pair> tag : collectedTags) { - PsiElement[] elements = tag.first.getDataElements(); - if (elements.length == 0) continue; - generateOneParameter(elements, buffer, tag); - } - buffer.append("
"); - } + generateParametersSection(buffer, CodeInsightBundle.message("javadoc.parameters"), collectedTags); } - private void generateTypeParametersSection(final StringBuilder buffer, final PsiMethod method) { - final PsiDocComment docComment = method.getDocComment(); - if (docComment == null) return; - final PsiDocTag[] localTags = docComment.findTagsByName("param"); + private void generateTypeParametersSection(final StringBuilder buffer, final PsiMethod method, PsiDocComment comment) { + final PsiDocTag[] localTags = comment == null ? PsiDocTag.EMPTY_ARRAY : comment.findTagsByName("param"); final PsiTypeParameter[] typeParameters = method.getTypeParameters(); - final LinkedList>> collectedTags = new LinkedList>>(); - for (PsiTypeParameter typeParameter : typeParameters) { + final LinkedList collectedTags = new LinkedList(); + for (int i = 0; i < typeParameters.length; i++) { + PsiTypeParameter typeParameter = typeParameters[i]; final String paramName = "<" + typeParameter.getName() + ">"; - Pair> parmTag = findDocTag(localTags, paramName, method); + DocTagLocator tagLocator = typeParameterLocator(i); + ParamInfo parmTag = findDocTag(localTags, paramName, method, tagLocator); if (parmTag != null) { collectedTags.addLast(parmTag); } } - generateTypeParametersSection(buffer, collectedTags); + generateParametersSection(buffer, CodeInsightBundle.message("javadoc.type.parameters"), collectedTags); } - private void generateTypeParametersSection(final StringBuilder buffer, final LinkedList>> collectedTags) { + private void generateParametersSection(StringBuilder buffer, String titleMessage, LinkedList collectedTags) { if (!collectedTags.isEmpty()) { buffer.append("
"); - buffer.append("
").append(CodeInsightBundle.message("javadoc.type.parameters")).append(""); - for (Pair> tag : collectedTags) { - PsiElement[] elements = tag.first.getDataElements(); - if (elements.length == 0) continue; - generateOneParameter(elements, buffer, tag); + buffer.append("
").append(titleMessage).append(""); + for (ParamInfo tag : collectedTags) { + generateOneParameter(buffer, tag); } buffer.append("
"); } } - @Nullable private Pair> findDocTag(final PsiDocTag[] localTags, - final String paramName, - final PsiMethod method) { - Pair> parmTag = null; - for (PsiDocTag localTag : localTags) { - PsiDocTagValue value = localTag.getValueElement(); - - if (value != null) { - String tagName = value.getText(); - - if (tagName != null && tagName.equals(paramName)) { - parmTag = - new Pair> - (localTag, - new InheritDocProvider() { - @Override - public Pair> getInheritDoc() { - return findInheritDocTag(method, parameterLocator(paramName)); - } - - @Override - public PsiClass getElement() { - return method.getContainingClass(); - } - }); - break; + @Nullable private ParamInfo findDocTag(final PsiDocTag[] localTags, + final String paramName, final PsiMethod method, final DocTagLocator tagLocator) { + PsiDocTag localTag = getTagByName(localTags, paramName); + if (localTag != null) { + return new ParamInfo(paramName, localTag, new InheritDocProvider() { + @Override + public Pair> getInheritDoc() { + return findInheritDocTag(method, tagLocator); } - } - } - if (parmTag == null) { - parmTag = findInheritDocTag(method, parameterLocator(paramName)); + @Override + public PsiClass getElement() { + return method.getContainingClass(); + } + }); } - return parmTag; + Pair> tag = findInheritDocTag(method, tagLocator); + return tag == null ? null : new ParamInfo(paramName, tag); } @SuppressWarnings({"HardCodedStringLiteral"}) - private void generateOneParameter(final PsiElement[] elements, - final StringBuilder buffer, - final Pair> tag) { + private void generateOneParameter(StringBuilder buffer, ParamInfo tag) { + PsiElement[] elements = tag.docTag.getDataElements(); + if (elements.length == 0) return; String text = elements[0].getText(); buffer.append("
"); int spaceIndex = text.indexOf(' '); if (spaceIndex < 0) { spaceIndex = text.length(); } - String parmName = text.substring(0, spaceIndex); buffer.append(""); - buffer.append(StringUtil.escapeXml(parmName)); + buffer.append(StringUtil.escapeXml(tag.name)); buffer.append(""); buffer.append(" - "); buffer.append(text.substring(spaceIndex)); - generateValue(buffer, elements, 1, mapProvider(tag.second, true)); + generateValue(buffer, elements, 1, mapProvider(tag.inheritDocTagProvider, true)); } @SuppressWarnings({"HardCodedStringLiteral"}) @@ -2073,7 +2068,7 @@ public class JavaDocInfoGenerator { final PsiMethod overriden = findMethodInSuperClass(method, aSuper); if (overriden != null) { - T tag = loc.find(getDocComment(overriden)); + T tag = loc.find(overriden, getDocComment(overriden)); if (tag != null) { return new Pair> @@ -2167,10 +2162,26 @@ public class JavaDocInfoGenerator { return findInheritDocTagInClass(method, aClass, loc, new HashSet()); } + + private static class ParamInfo { + private final String name; + private final PsiDocTag docTag; + private final InheritDocProvider inheritDocTagProvider; + + private ParamInfo(String paramName, PsiDocTag tag, InheritDocProvider provider) { + name = paramName; + docTag = tag; + inheritDocTagProvider = provider; + } + + private ParamInfo(String paramName, @NotNull Pair> tagWithInheritProvider) { + this(paramName, tagWithInheritProvider.first, tagWithInheritProvider.second); + } + } private static class ReturnTagLocator implements DocTagLocator { @Override - public PsiDocTag find(PsiDocComment comment) { + public PsiDocTag find(PsiDocCommentOwner owner, PsiDocComment comment) { if (comment == null) { return null; } diff --git a/java/java-tests/testData/codeInsight/javadocIG/matchingParameterNameFromParent.html b/java/java-tests/testData/codeInsight/javadocIG/matchingParameterNameFromParent.html new file mode 100644 index 000000000000..6e09c3961e7e --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/matchingParameterNameFromParent.html @@ -0,0 +1,2 @@ + Bar
+void m(int bar)
Overrides:
m in class Foo
Parameters:
bar - description
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/matchingParameterNameFromParent.java b/java/java-tests/testData/codeInsight/javadocIG/matchingParameterNameFromParent.java new file mode 100644 index 000000000000..78671d51eaee --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/matchingParameterNameFromParent.java @@ -0,0 +1,13 @@ +import java.lang.Override; + +class Foo { + /** + * @param foo description + */ + void m(int foo) {} +} + +class Bar extends Foo { + @Override + void m(int bar) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/matchingTypeParameterNameFromParent.html b/java/java-tests/testData/codeInsight/javadocIG/matchingTypeParameterNameFromParent.html new file mode 100644 index 000000000000..39ed7e32f77d --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/matchingTypeParameterNameFromParent.html @@ -0,0 +1,2 @@ + Bar
+<U> void m(U u)
Overrides:
m in class Foo
Type parameters:
<U> - description
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/javadocIG/matchingTypeParameterNameFromParent.java b/java/java-tests/testData/codeInsight/javadocIG/matchingTypeParameterNameFromParent.java new file mode 100644 index 000000000000..808b4f506ab7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/javadocIG/matchingTypeParameterNameFromParent.java @@ -0,0 +1,13 @@ +import java.lang.Override; + +class Foo { + /** + * @param description + */ + void m(T t) {} +} + +class Bar extends Foo { + @Override + void m(U u) {} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java index 165699bc59f3..6e5f94a36540 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java @@ -277,6 +277,20 @@ public class JavaDocInfoGeneratorTest extends CodeInsightTestCase { useJava7(); verifyJavaDoc(getTestClass()); } + + public void testMatchingParameterNameFromParent() throws Exception { + configureByFile("/codeInsight/javadocIG/" + getTestName(true) + ".java"); + PsiClass psiClass = ((PsiJavaFile)myFile).getClasses()[1]; + PsiMethod method = psiClass.getMethods()[0]; + verifyJavaDoc(method); + } + + public void testMatchingTypeParameterNameFromParent() throws Exception { + configureByFile("/codeInsight/javadocIG/" + getTestName(true) + ".java"); + PsiClass psiClass = ((PsiJavaFile)myFile).getClasses()[1]; + PsiMethod method = psiClass.getMethods()[0]; + verifyJavaDoc(method); + } @Override protected String getTestDataPath() {