Merge "Convert article delete to use OOUI"
[lhc/web/wiklou.git] / includes / parser / Parser.php
index b3e37a4..5da2546 100644 (file)
@@ -245,7 +245,7 @@ class Parser {
        public $currentRevisionCache;
 
        /**
-        * @var bool Recursive call protection.
+        * @var bool|string Recursive call protection.
         * This variable should be treated as if it were private.
         */
        public $mInParse = false;
@@ -550,7 +550,8 @@ class Parser {
                        // Since we're not really outputting HTML, decode the entities and
                        // then re-encode the things that need hiding inside HTML comments.
                        $limitReport = htmlspecialchars_decode( $limitReport );
-                       Hooks::run( 'ParserLimitReport', [ $this, &$limitReport ] );
+                       // Run deprecated hook
+                       Hooks::run( 'ParserLimitReport', [ $this, &$limitReport ], '1.22' );
 
                        // Sanitize for comment. Note '‐' in the replacement is U+2010,
                        // which looks much like the problematic '-'.
@@ -1074,7 +1075,6 @@ class Parser {
         * @return string
         */
        public function doTableStuff( $text ) {
-
                $lines = StringUtils::explode( "\n", $text );
                $out = '';
                $td_history = []; # Is currently a td tag open?
@@ -1278,7 +1278,6 @@ class Parser {
         * @return string
         */
        public function internalParse( $text, $isMain = true, $frame = false ) {
-
                $origText = $text;
 
                // Avoid PHP 7.1 warning from passing $this by reference
@@ -1854,7 +1853,6 @@ class Parser {
         * @return string
         */
        public function replaceExternalLinks( $text ) {
-
                $bits = preg_split( $this->mExtLinkBracketedRegex, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
                if ( $bits === false ) {
                        throw new MWException( "PCRE needs to be compiled with "
@@ -2242,12 +2240,6 @@ class Parser {
                                $link = $origLink;
                        }
 
-                       $noforce = ( substr( $origLink, 0, 1 ) !== ':' );
-                       if ( !$noforce ) {
-                               # Strip off leading ':'
-                               $link = substr( $link, 1 );
-                       }
-
                        $unstrip = $this->mStripState->unstripNoWiki( $link );
                        $nt = is_string( $unstrip ) ? Title::newFromText( $unstrip ) : null;
                        if ( $nt === null ) {
@@ -2258,6 +2250,8 @@ class Parser {
                        $ns = $nt->getNamespace();
                        $iw = $nt->getInterwiki();
 
+                       $noforce = ( substr( $origLink, 0, 1 ) !== ':' );
+
                        if ( $might_be_img ) { # if this is actually an invalid link
                                if ( $ns == NS_FILE && $noforce ) { # but might be an image
                                        $found = false;
@@ -2302,6 +2296,10 @@ class Parser {
                        $wasblank = ( $text == '' );
                        if ( $wasblank ) {
                                $text = $link;
+                               if ( !$noforce ) {
+                                       # Strip off leading ':'
+                                       $text = substr( $text, 1 );
+                               }
                        } else {
                                # T6598 madness. Handle the quotes only if they come from the alternate part
                                # [[Lista d''e paise d''o munno]] -> <a href="...">Lista d''e paise d''o munno</a>
@@ -2326,7 +2324,7 @@ class Parser {
                                        }
 
                                        $s = rtrim( $s . $prefix );
-                                       $s .= trim( $trail, "\n" ) == '' ? '': $prefix . $trail;
+                                       $s .= trim( $trail, "\n" ) == '' ? '' : $prefix . $trail;
                                        continue;
                                }
 
@@ -3030,7 +3028,6 @@ class Parser {
         * @return string The text of the template
         */
        public function braceSubstitution( $piece, $frame ) {
-
                // Flags
 
                // $text has been filled
@@ -3377,11 +3374,6 @@ class Parser {
 
                list( $callback, $flags ) = $this->mFunctionHooks[$function];
 
-               # Workaround for PHP bug 35229 and similar
-               if ( !is_callable( $callback ) ) {
-                       throw new MWException( "Tag hook for $function is not callable\n" );
-               }
-
                // Avoid PHP 7.1 warning from passing $this by reference
                $parser = $this;
 
@@ -3790,7 +3782,6 @@ class Parser {
         * @return array
         */
        public function argSubstitution( $piece, $frame ) {
-
                $error = false;
                $parts = $piece['parts'];
                $nameWithSpaces = $frame->expand( $piece['title'] );
@@ -3882,17 +3873,10 @@ class Parser {
                        }
 
                        if ( isset( $this->mTagHooks[$name] ) ) {
-                               # Workaround for PHP bug 35229 and similar
-                               if ( !is_callable( $this->mTagHooks[$name] ) ) {
-                                       throw new MWException( "Tag hook for $name is not callable\n" );
-                               }
                                $output = call_user_func_array( $this->mTagHooks[$name],
                                        [ $content, $attributes, $this, $frame ] );
                        } elseif ( isset( $this->mFunctionTagHooks[$name] ) ) {
                                list( $callback, ) = $this->mFunctionTagHooks[$name];
-                               if ( !is_callable( $callback ) ) {
-                                       throw new MWException( "Tag hook for $name is not callable\n" );
-                               }
 
                                // Avoid PHP 7.1 warning from passing $this by reference
                                $parser = $this;
@@ -3978,7 +3962,6 @@ class Parser {
         * @return string
         */
        public function doDoubleUnderscore( $text ) {
-
                # The position of __TOC__ needs to be recorded
                $mw = MagicWord::get( 'toc' );
                if ( $mw->match( $text ) ) {
@@ -4519,12 +4502,16 @@ class Parser {
                # which may corrupt this parser instance via its wfMessage()->text() call-
 
                # Signatures
-               $sigText = $this->getUserSig( $user );
-               $text = strtr( $text, [
-                       '~~~~~' => $d,
-                       '~~~~' => "$sigText $d",
-                       '~~~' => $sigText
-               ] );
+               if ( strpos( $text, '~~~' ) !== false ) {
+                       $sigText = $this->getUserSig( $user );
+                       $text = strtr( $text, [
+                               '~~~~~' => $d,
+                               '~~~~' => "$sigText $d",
+                               '~~~' => $sigText
+                       ] );
+                       # The main two signature forms used above are time-sensitive
+                       $this->mOutput->setFlag( 'user-signature' );
+               }
 
                # Context links ("pipe tricks"): [[|name]] and [[name (context)|]]
                $tc = '[' . Title::legalChars() . ']';
@@ -4761,7 +4748,7 @@ class Parser {
         * @throws MWException
         * @return callable|null The old value of the mTagHooks array associated with the hook
         */
-       public function setHook( $tag, $callback ) {
+       public function setHook( $tag, callable $callback ) {
                $tag = strtolower( $tag );
                if ( preg_match( '/[<>\r\n]/', $tag, $m ) ) {
                        throw new MWException( "Invalid character {$m[0]} in setHook('$tag', ...) call" );
@@ -4792,7 +4779,7 @@ class Parser {
         * @throws MWException
         * @return callable|null The old value of the mTagHooks array associated with the hook
         */
-       public function setTransparentTagHook( $tag, $callback ) {
+       public function setTransparentTagHook( $tag, callable $callback ) {
                $tag = strtolower( $tag );
                if ( preg_match( '/[<>\r\n]/', $tag, $m ) ) {
                        throw new MWException( "Invalid character {$m[0]} in setTransparentHook('$tag', ...) call" );
@@ -4855,7 +4842,7 @@ class Parser {
         * @throws MWException
         * @return string|callable The old callback function for this name, if any
         */
-       public function setFunctionHook( $id, $callback, $flags = 0 ) {
+       public function setFunctionHook( $id, callable $callback, $flags = 0 ) {
                global $wgContLang;
 
                $oldVal = isset( $this->mFunctionHooks[$id] ) ? $this->mFunctionHooks[$id][0] : null;
@@ -4907,7 +4894,7 @@ class Parser {
         * @throws MWException
         * @return null
         */
-       public function setFunctionTagHook( $tag, $callback, $flags ) {
+       public function setFunctionTagHook( $tag, callable $callback, $flags ) {
                $tag = strtolower( $tag );
                if ( preg_match( '/[<>\r\n]/', $tag, $m ) ) {
                        throw new MWException( "Invalid character {$m[0]} in setFunctionTagHook('$tag', ...) call" );
@@ -4959,7 +4946,6 @@ class Parser {
         * @return string HTML
         */
        public function renderImageGallery( $text, $params ) {
-
                $mode = false;
                if ( isset( $params['mode'] ) ) {
                        $mode = $params['mode'];
@@ -4974,6 +4960,7 @@ class Parser {
 
                $ig->setContextTitle( $this->mTitle );
                $ig->setShowBytes( false );
+               $ig->setShowDimensions( false );
                $ig->setShowFilename( false );
                $ig->setParser( $this );
                $ig->setHideBadImages();
@@ -6072,11 +6059,15 @@ class Parser {
        protected function lock() {
                if ( $this->mInParse ) {
                        throw new MWException( "Parser state cleared while parsing. "
-                               . "Did you call Parser::parse recursively?" );
+                               . "Did you call Parser::parse recursively? Lock is held by: " . $this->mInParse );
                }
-               $this->mInParse = true;
 
-               $recursiveCheck = new ScopedCallback( function() {
+               // Save the backtrace when locking, so that if some code tries locking again,
+               // we can print the lock owner's backtrace for easier debugging
+               $e = new Exception;
+               $this->mInParse = $e->getTraceAsString();
+
+               $recursiveCheck = new ScopedCallback( function () {
                        $this->mInParse = false;
                } );