Index: tests/phpunit/tests/formatting/FillEmptyLinks.php
===================================================================
--- tests/phpunit/tests/formatting/FillEmptyLinks.php	(revision 0)
+++ tests/phpunit/tests/formatting/FillEmptyLinks.php	(working copy)
@@ -0,0 +1,103 @@
+<?php
+/**
+ * @group formatting
+ */
+class Tests_Formatting_FillEmptyLinks extends WP_UnitTestCase {
+
+	/**
+	 * @ticket 12480
+	 */
+	public function test_content_with_link() {
+		$content = 'This <a href="http://example.com"></a>is a link';
+
+		$this->assertEquals(
+			'This <a href="http://example.com">http://example.com</a>is a link',
+			fill_empty_links( $content )
+		);
+	}
+
+	/**
+	 * @ticket 12480
+	 */
+	public function test_content_with_multiple_links() {
+		$content = 'This <a href="http://example.com"></a>is a link <a href="http://example.com/test"></a>';
+
+		$this->assertEquals(
+			'This <a href="http://example.com">http://example.com</a>is a link <a href="http://example.com/test">http://example.com/test</a>',
+			fill_empty_links( $content )
+		);
+	}
+
+	/**
+	 * Sanity check: verify we're not changing things when links aren't present.
+	 *
+	 * @ticket 12480
+	 */
+	public function test_content_without_links() {
+		$content = 'Lorem ipsum sit dolor';
+
+		$this->assertEquals( $content, fill_empty_links( $content ) );
+	}
+
+	/**
+	 * @ticket 12480
+	 */
+	public function test_content_with_whitespace() {
+		$this->assertEquals(
+			'This <a href="http://example.com">http://example.com</a>is a link',
+			fill_empty_links( 'This <a href="http://example.com"> </a>is a link' ),
+			'fill_empty_links() fails to match regular whitespace'
+		);
+
+		$this->assertEquals(
+			'This <a href="http://example.com">http://example.com</a>is a link',
+			fill_empty_links( 'This <a href="http://example.com">     </a>is a link' ),
+			'fill_empty_links() fails to match regular whitespaces'
+		);
+
+		$this->assertEquals(
+			'This <a href="http://example.com">http://example.com</a>is a link',
+			fill_empty_links( 'This <a href="http://example.com">&nbsp;</a>is a link' ),
+			'fill_empty_links() fails to match non-breaking whitespace'
+		);
+
+		$this->assertEquals(
+			'This <a href="http://example.com">http://example.com</a>is a link',
+			fill_empty_links( 'This <a href="http://example.com">&zwj;</a>is a link' ),
+			'fill_empty_links() fails to match zero-width joiner'
+		);
+
+		$this->assertEquals(
+			'This <a href="http://example.com">http://example.com</a>is a link',
+			fill_empty_links( 'This <a href="http://example.com">&zwnj;</a>is a link' ),
+			'fill_empty_links() fails to match zero-width non-joiner'
+		);
+	}
+
+	/**
+	 * @ticket 12480
+	 */
+	public function test__fill_empty_links() {
+		$matches = array(
+			'0' => 'This <a href="http://example.com"></a>is a link',
+			'1' => 'http://example.com',
+		);
+
+		$this->assertEquals(
+			'<a href="http://example.com">http://example.com</a>',
+			_fill_empty_links( $matches )
+		);
+	}
+
+	/**
+	 * @ticket 12480
+	 */
+	public function test__fill_empty_links_returns_false_for_invalid_data() {
+		$matches = array(
+			'0' => 'This <a href="http://example.com"></a>is a link',
+		);
+
+		$this->assertFalse(	_fill_empty_links( $matches ) );
+		$this->assertFalse( _fill_empty_links( 'just a string' ) );
+	}
+}

Property changes on: tests/phpunit/tests/formatting/FillEmptyLinks.php
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: src/wp-includes/default-filters.php
===================================================================
--- src/wp-includes/default-filters.php	(revision 36121)
+++ src/wp-includes/default-filters.php	(working copy)
@@ -147,6 +147,7 @@
 add_filter( 'comment_text', 'convert_chars'          );
 add_filter( 'comment_text', 'make_clickable',      9 );
 add_filter( 'comment_text', 'force_balance_tags', 25 );
+add_filter( 'comment_text', 'fill_empty_links',   24 );
 add_filter( 'comment_text', 'convert_smilies',    20 );
 add_filter( 'comment_text', 'wpautop',            30 );
 
Index: src/wp-includes/formatting.php
===================================================================
--- src/wp-includes/formatting.php	(revision 36121)
+++ src/wp-includes/formatting.php	(working copy)
@@ -1898,6 +1898,39 @@
 }
 
 /**
+ * Adds blank string to all HTML <a> empty elements in content.
+ *
+ * @since 4.5.0
+ *
+ * @param string $text Content that may contain HTML <a> elements.
+ * @return string Converted content.
+ */
+function fill_empty_links( $text ) {
+
+	// Matches any <a> elements with an 'href' attribute but no anchor text.
+	$regex = '#<a[^>]href="?([^"]*)"[^>]*>[\s|&nbsp;|&zwn?j;]*</a>#i';
+
+	return preg_replace_callback( $regex, '_fill_empty_links', $text );
+}
+
+/**
+ * Callback for preg_replace_callback() within fill_empty_links() to add a visual placeholder in
+ * comments with empty anchor text.
+ *
+ * @since 4.5.0
+ *
+ * @param array $matches An array of matches found by preg_replace_callback().
+ * @return string|bool A formatted anchor tag on success or a boolean FALSE if anything goes wrong.
+ */
+function _fill_empty_links( $matches ) {
+	if ( ! is_array( $matches ) || ! isset( $matches['1'] ) ) {
+		return false;
+	}
+
+	return sprintf( '<a href="%1$s">%1$s</a>', esc_url( $matches['1'] ) );
+}
+
+/**
  * Acts on text which is about to be edited.
  *
  * The $content is run through esc_textarea(), which uses htmlspecialchars()
