Bug 357325: [render] Method parameter annotations are not shown in
Javadoc hover/view
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/JavaElementLabelsTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/JavaElementLabelsTest.java
index f03e08a..163a38d 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/JavaElementLabelsTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/JavaElementLabelsTest.java
@@ -612,4 +612,43 @@
lab= JavaElementLabels.getTextLabel(elem, JavaElementLabels.M_PARAMETER_TYPES | JavaElementLabels.USE_RESOLVED);
assertEqualString(lab, "asList(Integer...)");
}
+
+
+ public void testMethodLabelAnnotatedParameters() throws Exception {
+ IPackageFragmentRoot sourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
+ IPackageFragment pack1= sourceFolder.createPackageFragment("org.test", false, null);
+ StringBuffer buf= new StringBuffer();
+ buf.append("package org.test;\n");
+ buf.append("\n");
+ buf.append("import java.lang.annotation.Retention;\n");
+ buf.append("import java.lang.annotation.RetentionPolicy;\n");
+ buf.append("\n");
+ buf.append("public class Annotations {\n");
+ buf.append(" void foo(@Outer(a=@Ann(\"Hello world\\r\\n\\t\\\"<'#@%^&\")) String param) { }\n");
+ buf.append(" \n");
+ buf.append(" void foo2(@Ann(value=\"\", cl=Annotations.class, ints={1, 2, -19},\n");
+ buf.append(" ch='\\0', sh= 0x7FFF, r= @Retention(RetentionPolicy.SOURCE)) String param) { }\n");
+ buf.append("}\n");
+ buf.append("@interface Ann {\n");
+ buf.append(" String value();\n");
+ buf.append(" Class<?> cl() default Ann.class;\n");
+ buf.append(" int[] ints() default {1, 2};\n");
+ buf.append(" char ch() default 'a';\n");
+ buf.append(" short sh() default 1;\n");
+ buf.append(" Retention r() default @Retention(RetentionPolicy.CLASS);\n");
+ buf.append("}\n");
+ buf.append("@interface Outer {\n");
+ buf.append(" Ann a();\n");
+ buf.append("}\n");
+ String content= buf.toString();
+ ICompilationUnit cu= pack1.createCompilationUnit("Annotations.java", content, false, null);
+
+ IJavaElement foo= cu.getElementAt(content.indexOf("foo"));
+ String lab= JavaElementLabels.getTextLabel(foo, JavaElementLabels.ALL_DEFAULT | JavaElementLabels.ALL_FULLY_QUALIFIED | JavaElementLabels.M_PARAMETER_ANNOTATIONS);
+ assertEqualString(lab, "org.test.Annotations.foo(@Outer(a=@Ann(value=\"Hello world\\r\\n\\t\\\"<'#@%^&\")) String)");
+
+ IJavaElement foo2= cu.getElementAt(content.indexOf("foo2"));
+ lab= JavaElementLabels.getTextLabel(foo2, JavaElementLabels.ALL_DEFAULT | JavaElementLabels.ALL_FULLY_QUALIFIED | JavaElementLabels.M_PARAMETER_ANNOTATIONS);
+ assertEqualString(lab, "org.test.Annotations.foo2(@Ann(value=\"\", cl=Annotations.class, ints={1, 2, -19}, ch='\\0', sh=32767, r=@Retention(value=RetentionPolicy.SOURCE)) String)");
+ }
}
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java
index 1e7dcd3..c7ab214 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java
@@ -38,6 +38,7 @@
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
@@ -45,6 +46,7 @@
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.BodyDeclaration;
+import org.eclipse.jdt.core.dom.CharacterLiteral;
import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
@@ -76,6 +78,7 @@
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.VariableDeclaration;
@@ -89,6 +92,7 @@
import org.eclipse.jdt.internal.corext.util.Strings;
import org.eclipse.jdt.internal.ui.JavaPlugin;
+import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
import org.eclipse.jdt.internal.ui.preferences.MembersOrderPreferenceCache;
import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
@@ -947,4 +951,30 @@
return null;
}
+ /**
+ * Escapes a string value to a literal that can be used in Java source.
+ *
+ * @param stringValue the string value
+ * @return the escaped string
+ * @see StringLiteral#getEscapedValue()
+ */
+ public static String getEscapedStringLiteral(String stringValue) {
+ StringLiteral stringLiteral= AST.newAST(ASTProvider.SHARED_AST_LEVEL).newStringLiteral();
+ stringLiteral.setLiteralValue(stringValue);
+ return stringLiteral.getEscapedValue();
+ }
+
+ /**
+ * Escapes a character value to a literal that can be used in Java source.
+ *
+ * @param ch the character value
+ * @return the escaped string
+ * @see CharacterLiteral#getEscapedValue()
+ */
+ public static String getEscapedCharacterLiteral(char ch) {
+ CharacterLiteral characterLiteral= AST.newAST(ASTProvider.SHARED_AST_LEVEL).newCharacterLiteral();
+ characterLiteral.setCharValue(ch);
+ return characterLiteral.getEscapedValue();
+ }
+
}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/infoviews/JavadocView.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/infoviews/JavadocView.java
index b783d2c..53f3c37 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/infoviews/JavadocView.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/infoviews/JavadocView.java
@@ -402,7 +402,7 @@
/** Flags used to render a label in the text widget. */
private static final long LABEL_FLAGS= JavaElementLabels.ALL_FULLY_QUALIFIED
- | JavaElementLabels.M_PRE_RETURNTYPE | JavaElementLabels.M_PARAMETER_TYPES | JavaElementLabels.M_PARAMETER_NAMES | JavaElementLabels.M_EXCEPTIONS
+ | JavaElementLabels.M_PRE_RETURNTYPE | JavaElementLabels.M_PARAMETER_ANNOTATIONS | JavaElementLabels.M_PARAMETER_TYPES | JavaElementLabels.M_PARAMETER_NAMES | JavaElementLabels.M_EXCEPTIONS
| JavaElementLabels.F_PRE_TYPE_SIGNATURE | JavaElementLabels.T_TYPE_PARAMETERS;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/hover/JavadocHover.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/hover/JavadocHover.java
index beaba82..593cd2b 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/hover/JavadocHover.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/hover/JavadocHover.java
@@ -66,10 +66,8 @@
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
-import org.eclipse.jdt.core.dom.CharacterLiteral;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ConstructorInvocation;
@@ -85,11 +83,11 @@
import org.eclipse.jdt.core.dom.QualifiedType;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
-import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.javadoc.JavaDocLocations;
import org.eclipse.jdt.internal.corext.util.JdtFlags;
import org.eclipse.jdt.internal.corext.util.Messages;
@@ -421,7 +419,7 @@
}
private static final long LABEL_FLAGS= JavaElementLabels.ALL_FULLY_QUALIFIED
- | JavaElementLabels.M_PRE_RETURNTYPE | JavaElementLabels.M_PARAMETER_TYPES | JavaElementLabels.M_PARAMETER_NAMES | JavaElementLabels.M_EXCEPTIONS
+ | JavaElementLabels.M_PRE_RETURNTYPE | JavaElementLabels.M_PARAMETER_ANNOTATIONS | JavaElementLabels.M_PARAMETER_TYPES | JavaElementLabels.M_PARAMETER_NAMES | JavaElementLabels.M_EXCEPTIONS
| JavaElementLabels.F_PRE_TYPE_SIGNATURE | JavaElementLabels.M_PRE_TYPE_PARAMETERS | JavaElementLabels.T_TYPE_PARAMETERS
| JavaElementLabels.USE_RESOLVED;
private static final long LOCAL_VARIABLE_FLAGS= LABEL_FLAGS & ~JavaElementLabels.F_FULLY_QUALIFIED | JavaElementLabels.F_POST_QUALIFIED;
@@ -766,10 +764,10 @@
return null;
if (constantValue instanceof String) {
- return getEscapedStringLiteral((String) constantValue);
+ return ASTNodes.getEscapedStringLiteral((String) constantValue);
} else if (constantValue instanceof Character) {
- String constantResult= getEscapedCharacterLiteral(((Character) constantValue).charValue());
+ String constantResult= ASTNodes.getEscapedCharacterLiteral(((Character) constantValue).charValue());
char charValue= ((Character) constantValue).charValue();
String hexString= Integer.toHexString(charValue);
@@ -812,23 +810,6 @@
return NodeFinder.perform(unit, hoverRegion.getOffset(), hoverRegion.getLength());
}
- private static String getEscapedStringLiteral(String stringValue) {
- StringLiteral stringLiteral= AST.newAST(ASTProvider.SHARED_AST_LEVEL).newStringLiteral();
- stringLiteral.setLiteralValue(stringValue);
- String stringConstant= stringLiteral.getEscapedValue();
- if (stringConstant.length() > 80) {
- return stringConstant.substring(0, 80) + JavaElementLabels.ELLIPSIS_STRING;
- } else {
- return stringConstant;
- }
- }
-
- private static String getEscapedCharacterLiteral(char ch) {
- CharacterLiteral characterLiteral= AST.newAST(ASTProvider.SHARED_AST_LEVEL).newCharacterLiteral();
- characterLiteral.setCharValue(ch);
- return characterLiteral.getEscapedValue();
- }
-
/**
* Creates and returns a formatted message for the given
* constant with its hex value.
@@ -1062,6 +1043,7 @@
}
private static void addValue(StringBuffer buf, IJavaElement element, Object value) throws URISyntaxException {
+ // Note: To be bug-compatible with Javadoc from Java 5/6/7, we currently don't escape HTML tags in String-valued annotations.
if (value instanceof ITypeBinding) {
ITypeBinding typeBinding= (ITypeBinding)value;
IJavaElement type= typeBinding.getJavaElement();
@@ -1086,10 +1068,10 @@
addAnnotation(buf, element, annotationBinding);
} else if (value instanceof String) {
- buf.append(getEscapedStringLiteral((String)value));
+ buf.append(ASTNodes.getEscapedStringLiteral((String)value));
} else if (value instanceof Character) {
- buf.append(getEscapedCharacterLiteral(((Character)value).charValue()));
+ buf.append(ASTNodes.getEscapedCharacterLiteral(((Character)value).charValue()));
} else if (value instanceof Object[]) {
Object[] values= (Object[])value;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/JavaElementLabelComposer.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/JavaElementLabelComposer.java
index 3c4ab9b..5f45c5e 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/JavaElementLabelComposer.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/JavaElementLabelComposer.java
@@ -27,6 +27,7 @@
import org.eclipse.jdt.core.BindingKey;
import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
@@ -35,6 +36,7 @@
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.IMember;
+import org.eclipse.jdt.core.IMemberValuePair;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
@@ -43,6 +45,7 @@
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.Messages;
@@ -212,7 +215,7 @@
private static String fgPkgNameAbbreviationPattern= ""; //$NON-NLS-1$
private static PackageNameAbbreviation[] fgPkgNameAbbreviation;
- private final FlexibleBuffer fBuffer;
+ protected final FlexibleBuffer fBuffer;
private static final boolean getFlag(long flags, long flag) {
return (flags & flag) != 0;
@@ -429,11 +432,20 @@
}
}
}
+
+ ILocalVariable[] annotatedParameters= null;
+ if (nParams > 0 && getFlag(flags, JavaElementLabels.M_PARAMETER_ANNOTATIONS)) {
+ annotatedParameters= method.getParameters();
+ }
for (int i= 0; i < nParams; i++) {
if (i > 0) {
fBuffer.append(JavaElementLabels.COMMA_STRING);
}
+ if (annotatedParameters != null && i < annotatedParameters.length) {
+ appendAnnotationLabels(annotatedParameters[i].getAnnotations(), flags);
+ }
+
if (types != null) {
String paramSig= types[i];
if (renderVarargs && (i == nParams - 1)) {
@@ -541,6 +553,79 @@
}
}
+ protected void appendAnnotationLabels(IAnnotation[] annotations, long flags) throws JavaModelException {
+ for (int j= 0; j < annotations.length; j++) {
+ IAnnotation annotation= annotations[j];
+ appendAnnotationLabel(annotation, flags);
+ fBuffer.append(' ');
+ }
+ }
+
+ public void appendAnnotationLabel(IAnnotation annotation, long flags) throws JavaModelException {
+ fBuffer.append('@');
+ appendTypeSignatureLabel(annotation, Signature.createTypeSignature(annotation.getElementName(), false), flags);
+ IMemberValuePair[] memberValuePairs= annotation.getMemberValuePairs();
+ if (memberValuePairs.length == 0)
+ return;
+ fBuffer.append('(');
+ for (int i= 0; i < memberValuePairs.length; i++) {
+ if (i > 0)
+ fBuffer.append(JavaElementLabels.COMMA_STRING);
+ IMemberValuePair memberValuePair= memberValuePairs[i];
+ fBuffer.append(getMemberName(annotation, annotation.getElementName(), memberValuePair.getMemberName()));
+ fBuffer.append('=');
+ appendAnnotationValue(annotation, memberValuePair.getValue(), memberValuePair.getValueKind(), flags);
+ }
+ fBuffer.append(')');
+ }
+
+ private void appendAnnotationValue(IAnnotation annotation, Object value, int valueKind, long flags) throws JavaModelException {
+ // Note: To be bug-compatible with Javadoc from Java 5/6/7, we currently don't escape HTML tags in String-valued annotations.
+ if (value instanceof Object[]) {
+ fBuffer.append('{');
+ Object[] values= (Object[]) value;
+ for (int j= 0; j < values.length; j++) {
+ if (j > 0)
+ fBuffer.append(JavaElementLabels.COMMA_STRING);
+ value= values[j];
+ appendAnnotationValue(annotation, value, valueKind, flags);
+ }
+ fBuffer.append('}');
+ } else {
+ switch (valueKind) {
+ case IMemberValuePair.K_CLASS:
+ appendTypeSignatureLabel(annotation, Signature.createTypeSignature((String) value, false), flags);
+ fBuffer.append(".class"); //$NON-NLS-1$
+ break;
+ case IMemberValuePair.K_QUALIFIED_NAME:
+ String name = (String) value;
+ int lastDot= name.lastIndexOf('.');
+ if (lastDot != -1) {
+ String type= name.substring(0, lastDot);
+ String field= name.substring(lastDot + 1);
+ appendTypeSignatureLabel(annotation, Signature.createTypeSignature(type, false), flags);
+ fBuffer.append('.');
+ fBuffer.append(getMemberName(annotation, type, field));
+ break;
+ }
+// case IMemberValuePair.K_SIMPLE_NAME: // can't implement, since parent type is not known
+ //$FALL-THROUGH$
+ case IMemberValuePair.K_ANNOTATION:
+ appendAnnotationLabel((IAnnotation) value, flags);
+ break;
+ case IMemberValuePair.K_STRING:
+ fBuffer.append(ASTNodes.getEscapedStringLiteral((String) value));
+ break;
+ case IMemberValuePair.K_CHAR:
+ fBuffer.append(ASTNodes.getEscapedCharacterLiteral(((Character) value).charValue()));
+ break;
+ default:
+ fBuffer.append(String.valueOf(value));
+ break;
+ }
+ }
+ }
+
private void appendCategoryLabel(IMember member, long flags) throws JavaModelException {
String[] categories= member.getCategories();
if (categories.length > 0) {
@@ -790,6 +875,18 @@
return Signature.getSimpleName(Signature.toString(Signature.getTypeErasure(typeSig)));
}
+ /**
+ * Returns the simple name of the given member.
+ *
+ * @param enclosingElement the enclosing element
+ * @param typeName the name of the member's declaring type
+ * @param memberName the name of the member
+ * @return the simple name of the member
+ */
+ protected String getMemberName(IJavaElement enclosingElement, String typeName, String memberName) {
+ return memberName;
+ }
+
private void appendTypeArgumentSignaturesLabel(IJavaElement enclosingElement, String[] typeArgsSig, long flags) {
if (typeArgsSig.length > 0) {
fBuffer.append(getLT());
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/JavaElementLinks.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/JavaElementLinks.java
index 7fc01fa..29175d0 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/JavaElementLinks.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/JavaElementLinks.java
@@ -144,6 +144,24 @@
return typeName;
}
}
+
+ @Override
+ protected String getMemberName(IJavaElement enclosingElement, String typeName, String memberName) {
+ try {
+ String uri= createURI(JAVADOC_SCHEME, enclosingElement, typeName, memberName, null);
+ return createHeaderLink(uri, memberName);
+ } catch (URISyntaxException e) {
+ JavaPlugin.log(e);
+ return memberName;
+ }
+ }
+
+ @Override
+ protected void appendAnnotationLabels(IAnnotation[] annotations, long flags) throws JavaModelException {
+ fBuffer.append("<span style='font-weight:normal;'>"); //$NON-NLS-1$
+ super.appendAnnotationLabels(annotations, flags);
+ fBuffer.append("</span>"); //$NON-NLS-1$
+ }
}
public static final String OPEN_LINK_SCHEME= "eclipse-open"; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/JavaElementLabels.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/JavaElementLabels.java
index e422ec2..93f2772 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/JavaElementLabels.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/JavaElementLabels.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -74,6 +74,14 @@
public final static long M_PARAMETER_NAMES= 1L << 1;
/**
+ * Method labels contain parameter annotations.
+ * E.g. <code>foo(@NonNull int)</code>.
+ * This flag is only valid if {@link #M_PARAMETER_NAMES} or {@link #M_PARAMETER_TYPES} is also set.
+ * @since 3.8
+ */
+ public final static long M_PARAMETER_ANNOTATIONS= 1L << 52;
+
+ /**
* Method names contain type parameters prepended.
* e.g. <code><A> foo(A index)</code>
*/