Bug 499647: [null] Annotate command on constructor parameter creates
wrong entry in .eea

- includes resolving some warnings

Change-Id: I6ec3737f8bc438fe8900ec9e0e3a50178f170847
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AbstractAnnotateAssistTests.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AbstractAnnotateAssistTests.java
index 16a0092..376be07 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AbstractAnnotateAssistTests.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AbstractAnnotateAssistTests.java
@@ -125,23 +125,20 @@
 	// === from PropertiesFileQuickAssistTest: ===
 
 	protected static void checkContentOfFile(String message, IFile file, String content) throws Exception {
-		InputStream in= file.getContents();
-		try {
+		try (InputStream in= file.getContents()) {
 			assertEqualLines(message, content, copyToString(in));
-		} finally {
-			in.close();
 		}
 	}
 
 	protected static String copyToString(InputStream in) throws Exception {
-		ByteArrayOutputStream out= new ByteArrayOutputStream();
-		int read= in.read();
-		while (read != -1) {
-			out.write(read);
-			read= in.read();
+		try (ByteArrayOutputStream out= new ByteArrayOutputStream()) {
+			int read= in.read();
+			while (read != -1) {
+				out.write(read);
+				read= in.read();
+			}
+			return out.toString();
 		}
-		out.close();
-		return out.toString();
 	}
 
 	protected static void assertEqualLines(String message, String expected, String actual) {
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest15.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest15.java
index f191de3..f2e11e0 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest15.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest15.java
@@ -414,6 +414,75 @@
 	}
 
 	/*
+	 * Assert two proposals ("@NonNull" and "@Nullable") on a parameter of a constructor.
+	 * Apply the second proposal and check the effect.
+	 */
+	public void testAnnotateConstructorParameter() throws Exception {
+		
+		String X_PATH= "pack/age/X";
+		String[] pathAndContents= new String[] {
+					X_PATH+".java",
+					"package pack.age;\n" +
+					"import java.util.List;\n" +
+					"public class X {\n" +
+					"    public X(String p) {}\n" +
+					"}\n"
+				};
+		addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5, null);
+		
+		IFile annotationFile= fJProject1.getProject().getFile(new Path(ANNOTATION_PATH).append(X_PATH+".eea"));
+		String initialContent=
+				"class pack/age/X\n" +
+				"<init>\n" +
+				" (Ljava/lang/String;)V\n";
+		ensureExists(annotationFile.getParent());
+		annotationFile.create(new ByteArrayInputStream(initialContent.getBytes("UTF-8")), 0, null);
+
+		IType type= fJProject1.findType(X_PATH.replace('/', '.'));
+		JavaEditor javaEditor= (JavaEditor) JavaUI.openInEditor(type);
+
+		try {
+			int offset= pathAndContents[1].indexOf("String");
+
+			List<ICompletionProposal> list= collectAnnotateProposals(javaEditor, offset);
+			
+			assertCorrectLabels(list);
+			assertNumberOfProposals(list, 2);
+			
+			ICompletionProposal proposal= findProposalByName("Annotate as '@NonNull String'", list);
+			String expectedInfo=
+					"<dl><dt>&lt;init&gt;</dt>" +
+					"<dd>(Ljava/lang/String;)V</dd>" +
+					"<dd>(L<b>1</b>java/lang/String;)V</dd>" + // <= 1
+					"</dl>";
+			assertEquals("expect detail", expectedInfo, proposal.getAdditionalProposalInfo());
+
+			proposal= findProposalByName("Annotate as '@Nullable String'", list);
+			expectedInfo=
+					"<dl><dt>&lt;init&gt;</dt>" +
+					"<dd>(Ljava/lang/String;)V</dd>" +
+					"<dd>(L<b>0</b>java/lang/String;)V</dd>" + // <= 0
+					"</dl>";
+			assertEquals("expect detail", expectedInfo, proposal.getAdditionalProposalInfo());
+
+			IDocument document= javaEditor.getDocumentProvider().getDocument(javaEditor.getEditorInput());
+			proposal.apply(document);
+			
+			annotationFile= fJProject1.getProject().getFile(new Path(ANNOTATION_PATH).append(X_PATH+".eea"));
+			assertTrue("Annotation file should have been created", annotationFile.exists());
+
+			String expectedContent=
+					"class pack/age/X\n" +
+					"<init>\n" +
+					" (Ljava/lang/String;)V\n" +
+					" (L0java/lang/String;)V\n";
+			checkContentOfFile("annotation file content", annotationFile, expectedContent);
+		} finally {
+			JavaPlugin.getActivePage().closeAllEditors(false);
+		}
+	}
+
+	/*
 	 * Assert two proposals ("@NonNull" and "@Nullable") on a simple field type (type variable).
 	 * Apply the second proposal and check the effect.
 	 */
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest18.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest18.java
index 153b9d5..490b329 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest18.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest18.java
@@ -60,7 +60,7 @@
 	 * Assert two proposals ("@NonNull" and "@Nullable") on a type argument of a parameter.
 	 * The parameterized type already has a @NonNull annotation.
 	 * Apply the second proposal and check the effect.
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	public void testAnnotateParameter_TypeArgument() throws Exception {
 		
@@ -130,7 +130,7 @@
 
 	/**
 	 * Assert NO proposals on the primitive leaf type of an array type.
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	public void testAnnotateParameter_ArrayOfPrimitive() throws Exception {
 		
@@ -163,7 +163,7 @@
 	 * The parameterized type and the wildcard already has a @NonNull annotation.
 	 * Annotation entry already exists, with @NonNull on the wildcard itself.
 	 * Apply the second proposal and check the effect.
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	public void testAnnotateParameter_WildcardBound() throws Exception {
 		
@@ -237,7 +237,7 @@
 	 * Apply the second proposal and check the effect.
 	 * 
 	 * Cf. {@link AnnotateAssistTest15#testAnnotateParameter_Array1()}
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	public void testAnnotateParameter_Array2() throws Exception {
 		
@@ -309,7 +309,7 @@
 	 * Apply the second proposal and check the effect.
 	 * 
 	 * Cf. {@link AnnotateAssistTest15#testAnnotateParameter_Array1()}
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	public void testAnnotateParameter_Array3() throws Exception {
 		
@@ -383,7 +383,7 @@
 	 * Apply the second proposal and check the effect.
 	 * 
 	 * Cf. {@link AnnotateAssistTest18#testAnnotateParameter_Array3()}
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	public void testAnnotateParameter_Array4() throws Exception {
 		
@@ -457,7 +457,7 @@
 	 * Apply the second proposal and check the effect.
 	 * 
 	 * Cf. {@link AnnotateAssistTest18#testAnnotateParameter_Array3()}
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	public void testAnnotateParameter_Array5() throws Exception {
 		
@@ -530,7 +530,7 @@
 	 * Apply the second proposal and check the effect.
 	 * 
 	 * Cf. {@link AnnotateAssistTest18#testAnnotateParameter_Array3()}
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	public void testAnnotateParameter_Varargs1() throws Exception {
 		
@@ -603,7 +603,7 @@
 	 * Apply the second proposal and check the effect.
 	 * 
 	 * Cf. {@link AnnotateAssistTest18#testAnnotateParameter_Varargs1()}
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	public void testAnnotateParameter_Varargs2() throws Exception {
 		
@@ -676,7 +676,7 @@
 	 * The parameterized type and the wildcard already has a @NonNull annotation.
 	 * Annotation entry already exists, with @NonNull on the wildcard itself.
 	 * Apply the second proposal and check the effect.
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	// FIXME(stephan): enable once implemented
 	public void _testAnnotateParameter_TypeParameter() throws Exception {
@@ -739,7 +739,7 @@
 	/**
 	 * Assert two proposals ("@NonNull" and "@Nullable") on a complex field type (list of array)
 	 * Apply the second proposal and check the effect.
-	 * @throws Exception
+	 * @throws Exception multiple causes
 	 */
 	public void testAnnotateField1() throws Exception {
 		
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ExternalNullAnnotationChangeProposals.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ExternalNullAnnotationChangeProposals.java
index 3c1b775..b27b845 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ExternalNullAnnotationChangeProposals.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ExternalNullAnnotationChangeProposals.java
@@ -96,6 +96,8 @@
  */
 public class ExternalNullAnnotationChangeProposals {
 
+	static final String CONSTRUCTOR_SELECTOR= "<init>"; //$NON-NLS-1$
+
 	static abstract class SignatureAnnotationChangeProposal implements IJavaCompletionProposal, ICommandAccess {
 
 		protected String fLabel;
@@ -200,7 +202,7 @@
 		public String getAdditionalProposalInfo() {
 			StringBuffer buffer= new StringBuffer();
 			buffer.append("<dl>"); //$NON-NLS-1$
-			buffer.append("<dt>").append(fSelector).append("</dt>"); //$NON-NLS-1$ //$NON-NLS-2$
+			buffer.append("<dt>").append(getHtmlRepresentation(fSelector)).append("</dt>"); //$NON-NLS-1$ //$NON-NLS-2$
 			buffer.append("<dd>").append(getHtmlRepresentation(fSignature)).append("</dd>"); //$NON-NLS-1$ //$NON-NLS-2$
 			buffer.append("<dd>").append(getFullAnnotatedSignatureHTML()).append("</dd>"); //$NON-NLS-1$ //$NON-NLS-2$
 			buffer.append("</dl>"); //$NON-NLS-1$
@@ -341,7 +343,7 @@
 		return binding;
 	}
 
-	/* Quick assist on class file, propose changes an any type detail. */
+	/* Quick assist on class file, propose changes on any type detail. */
 	public static void collectExternalAnnotationProposals(ICompilationUnit cu, ASTNode coveringNode, int offset, ArrayList<IJavaCompletionProposal> resultingCollection) {
 
 		IJavaProject javaProject= cu.getJavaProject();
@@ -392,7 +394,7 @@
 				if (coveringNode == null)
 					return;
 			}
-			if (inner.getNodeType() == ASTNode.PRIMITIVE_TYPE)
+			if (inner == null || inner.getNodeType() == ASTNode.PRIMITIVE_TYPE)
 				return; // cannot be annotated
 			outer= inner;
 			ASTNode next;
@@ -539,7 +541,9 @@
 		int fParamIdx;
 
 		ParameterProposalCreator(ICompilationUnit cu, IMethodBinding methodBinding, int paramIdx) {
-			super(cu, methodBinding.getDeclaringClass(), methodBinding.getName(), extractGenericSignature(methodBinding));
+			super(cu, methodBinding.getDeclaringClass(),
+					methodBinding.isConstructor() ? CONSTRUCTOR_SELECTOR : methodBinding.getName(),
+					extractGenericSignature(methodBinding));
 			fParamIdx= paramIdx;
 		}