*
* @since 1.17
*
- * @param mixed ... Parameters as strings, or a single argument that is
- * an array of strings.
+ * @param mixed ... Parameters as strings or arrays from
+ * Message::numParam() and the like, or a single array of parameters.
*
* @return Message $this
*/
public function params( /*...*/ ) {
$args = func_get_args();
- if ( isset( $args[0] ) && is_array( $args[0] ) ) {
- $args = $args[0];
+
+ // If $args has only one entry and it's an array, then it's either a
+ // non-varargs call or it happens to be a call with just a single
+ // "special" parameter. Since the "special" parameters don't have any
+ // numeric keys, we'll test that to differentiate the cases.
+ if ( count( $args ) === 1 && isset( $args[0] ) && is_array( $args[0] ) ) {
+ if ( $args[0] === [] ) {
+ $args = [];
+ } else {
+ foreach ( $args[0] as $key => $value ) {
+ if ( is_int( $key ) ) {
+ $args = $args[0];
+ break;
+ }
+ }
+ }
}
- $args_values = array_values( $args );
- $this->parameters = array_merge( $this->parameters, $args_values );
+
+ $this->parameters = array_merge( $this->parameters, array_values( $args ) );
return $this;
}
$pixels = $context->msg( 'unit-pixel' )->text();
foreach ( $context->getConfig()->get( 'ImageLimits' ) as $index => $limits ) {
- $display = "{$limits[0]}×{$limits[1]}" . $pixels;
+ // Note: A left-to-right marker (\u200e) is inserted, see T144386
+ $display = "{$limits[0]}" . json_decode( '"\u200e"' ) . "×{$limits[1]}" . $pixels;
$ret[$display] = $index;
}
* @return string
*/
function openStream() {
- global $wgLanguageCode;
+ global $wgContLang;
$ver = WikiExporter::schemaVersion();
return Xml::element( 'mediawiki', [
'xmlns' => "http://www.mediawiki.org/xml/export-$ver/",
'xsi:schemaLocation' => "http://www.mediawiki.org/xml/export-$ver/ " .
"http://www.mediawiki.org/xml/export-$ver.xsd",
'version' => $ver,
- 'xml:lang' => $wgLanguageCode ],
+ 'xml:lang' => $wgContLang->getHtmlCode() ],
null ) .
"\n" .
$this->siteInfo();
'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
[ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
[ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
+
+ // 1.29
+ [ 'addField', 'externallinks', 'el_index_60', 'patch-externallinks-el_index_60.sql' ],
];
}
[ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
[ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
[ 'modifyField', 'recentchanges', 'rc_ip', 'patch-rc_ip_modify.sql' ],
+
+ // 1.29
+ [ 'addField', 'externallinks', 'el_index_60', 'patch-externallinks-el_index_60.sql' ],
];
}
[ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
[ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
+ // 1.29
+ [ 'addField', 'externallinks', 'el_index_60', 'patch-externallinks-el_index_60.sql' ],
+
// KEEP THIS AT THE BOTTOM!!
[ 'doRebuildDuplicateFunction' ],
"INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('change_tag_ct_id_seq')" ],
[ 'addPgField', 'tag_summary', 'ts_id',
"INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('tag_summary_ts_id_seq')" ],
+
+ // 1.29
+ [ 'addPgField', 'externallinks', 'el_index_60', "BYTEA NOT NULL DEFAULT ''" ],
+ [ 'addPgIndex', 'externallinks', 'el_index_60', '( el_index_60, el_id )' ],
+ [ 'addPgIndex', 'externallinks', 'el_from_index_60', '( el_from, el_index_60, el_id )' ],
];
}
'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
[ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
[ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
+
+ // 1.29
+ [ 'addField', 'externallinks', 'el_index_60', 'patch-externallinks-el_index_60.sql' ],
];
}
# Constants needed for external link processing
# Everything except bracket, space, or control characters
# \p{Zs} is unicode 'separator, space' category. It covers the space 0x20
- # as well as U+3000 is IDEOGRAPHIC SPACE for bug 19052
+ # as well as U+3000 is IDEOGRAPHIC SPACE for T21052
const EXT_LINK_URL_CLASS = '[^][<>"\\x00-\\x20\\x7F\p{Zs}]';
# Simplified expression to match an IPv4 or IPv6 address, or
# at least one character of a host name (embeds EXT_LINK_URL_CLASS)
# Preprocessor_Hash is much faster than Preprocessor_DOM under HipHop
$this->mPreprocessorClass = 'Preprocessor_Hash';
} elseif ( extension_loaded( 'domxml' ) ) {
- # PECL extension that conflicts with the core DOM extension (bug 13770)
+ # PECL extension that conflicts with the core DOM extension (T15770)
wfDebug( "Warning: you have the obsolete domxml extension for PHP. Please remove it!\n" );
$this->mPreprocessorClass = 'Preprocessor_Hash';
} elseif ( extension_loaded( 'dom' ) ) {
public function __clone() {
$this->mInParse = false;
- // Bug 56226: When you create a reference "to" an object field, that
+ // T58226: When you create a reference "to" an object field, that
// makes the object field itself be a reference too (until the other
// reference goes out of scope). When cloning, any field that's a
// reference is copied as a reference in the new object. Both of these
$this->mStripState = new StripState;
- # Clear these on every parse, bug 4549
+ # Clear these on every parse, T6549
$this->mTplRedirCache = $this->mTplDomCache = [];
$this->mShowToc = true;
}
/**
- * Process the wikitext for the "?preload=" feature. (bug 5210)
+ * Process the wikitext for the "?preload=" feature. (T7210)
*
* "<noinclude>", "<includeonly>" etc. are parsed as for template
* transclusion, comments, templates, arguments, tags hooks and parser
# A cell could contain both parameters and data
$cell_data = explode( '|', $cell, 2 );
- # Bug 553: Note that a '|' inside an invalid link should not
+ # T2553: Note that a '|' inside an invalid link should not
# be mistaken as delimiting cell parameters
if ( strpos( $cell_data[0], '[[' ) !== false ) {
$cell = "{$previous}<{$last_tag}>{$cell}";
# Clean up special characters, only run once, next-to-last before doBlockLevels
$fixtags = [
- # french spaces, last one Guillemet-left
+ # French spaces, last one Guillemet-left
# only if there is something before the space
'/(.) (?=\\?|:|;|!|%|\\302\\273)/' => '\\1 ',
# french spaces, Guillemet-right
'/(\\302\\253) /' => '\\1 ',
- '/ (!\s*important)/' => ' \\1', # Beware of CSS magic word !important, bug #11874.
+ '/ (!\s*important)/' => ' \\1', # Beware of CSS magic word !important, T13874.
];
$text = preg_replace( array_keys( $fixtags ), array_values( $fixtags ), $text );
}
} else {
# attempt to sanitize at least some nesting problems
- # (bug #2702 and quite a few others)
+ # (T4702 and quite a few others)
$tidyregs = [
# ''Something [http://www.cool.com cool''] -->
# <i>Something</i><a href="http://www.cool.com"..><i>cool></i></a>
'/(<([bi])>)(<([bi])>)?([^<]*)(<\/?a[^<]*>)([^<]*)(<\/\\4>)?(<\/\\2>)/' =>
'\\1\\3\\5\\8\\9\\6\\1\\3\\7\\8\\9',
# fix up an anchor inside another anchor, only
- # at least for a single single nested link (bug 3695)
+ # at least for a single single nested link (T5695)
'/(<a[^>]+>)([^<]*)(<a[^>]+>[^<]*)<\/a>(.*)<\/a>/' =>
'\\1\\2</a>\\3</a>\\1\\4</a>',
# fix div inside inline elements- doBlockLevels won't wrap a line which
$thislen = strlen( $arr[$i] );
// If there are ever four apostrophes, assume the first is supposed to
// be text, and the remaining three constitute mark-up for bold text.
- // (bug 13227: ''''foo'''' turns into ' ''' foo ' ''')
+ // (T15227: ''''foo'''' turns into ' ''' foo ' ''')
if ( $thislen == 4 ) {
$arr[$i - 1] .= "'";
$arr[$i] = "'''";
} elseif ( $thislen > 5 ) {
// If there are more than 5 apostrophes in a row, assume they're all
// text except for the last 5.
- // (bug 13227: ''''''foo'''''' turns into ' ''''' foo ' ''''')
+ // (T15227: ''''''foo'''''' turns into ' ''''' foo ' ''''')
$arr[$i - 1] .= str_repeat( "'", $thislen - 5 );
$arr[$i] = "'''''";
$thislen = 5;
# If we get a ] at the beginning of $m[3] that means we have a link that's something like:
# [[Image:Foo.jpg|[http://example.com desc]]] <- having three ] in a row fucks up,
# the real problem is with the $e1 regex
- # See bug 1300.
+ # See T1500.
# Still some problems for cases where the ] is meant to be outside punctuation,
- # and no image is in sight. See bug 2095.
+ # and no image is in sight. See T4095.
if ( $text !== ''
&& substr( $m[3], 0, 1 ) === ']'
&& strpos( $text, '[' ) !== false
if ( $wasblank ) {
$text = $link;
} else {
- # Bug 4598 madness. Handle the quotes only if they come from the alternate part
+ # 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>
# [[Criticism of Harry Potter|Criticism of ''Harry Potter'']]
# -> <a href="Criticism of Harry Potter">Criticism of <i>Harry Potter</i></a>
in_array( $iw, $wgExtraInterlanguageLinkPrefixes )
)
) {
- # Bug 24502: filter duplicates
+ # T26502: filter duplicates
if ( !isset( $this->mLangLinkLanguages[$iw] ) ) {
$this->mLangLinkLanguages[$iw] = true;
$this->mOutput->addLanguageLink( $nt->getFullText() );
continue;
}
} elseif ( $ns == NS_CATEGORY ) {
- $s = rtrim( $s . "\n" ); # bug 87
+ $s = rtrim( $s . "\n" ); # T2087
if ( $wasblank ) {
$sortkey = $this->getDefaultSort();
$this->mOutput->addCategory( $nt->getDBkey(), $sortkey );
/**
- * Strip the whitespace Category links produce, see bug 87
+ * Strip the whitespace Category links produce, see T2087
*/
$s .= trim( $prefix . $trail, "\n" ) == '' ? '' : $prefix . $trail;
$subjPage = $this->mTitle->getSubjectPage();
$value = wfEscapeWikiText( $subjPage->getPrefixedURL() );
break;
- case 'pageid': // requested in bug 23427
+ case 'pageid': // requested in T25427
$pageid = $this->getTitle()->getArticleID();
if ( $pageid == 0 ) {
# 0 means the page doesn't exist in the database,
$value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'H' ), true );
break;
case 'currentweek':
- # @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to
+ # @bug T6594 PHP5 has it zero padded, PHP4 does not, cast to
# int to remove the padding
$value = $pageLang->formatNum( (int)MWTimestamp::getInstance( $ts )->format( 'W' ) );
break;
$value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'H' ), true );
break;
case 'localweek':
- # @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to
+ # @bug T6594 PHP5 has it zero padded, PHP4 does not, cast to
# int to remove the padding
$value = $pageLang->formatNum( (int)MWTimestamp::getLocalInstance( $ts )->format( 'W' ) );
break;
* included. Default is to assume a direct page view.
*
* The generated DOM tree must depend only on the input text and the flags.
- * The DOM tree must be the same in OT_HTML and OT_WIKI mode, to avoid a regression of bug 4899.
+ * The DOM tree must be the same in OT_HTML and OT_WIKI mode, to avoid a regression of T6899.
*
* Any flag added to the $flags parameter here, or any other parameter liable to cause a
* change in the DOM tree for a given text, must be passed through the section identifier
&& !$piece['lineStart']
&& preg_match( '/^(?:{\\||:|;|#|\*)/', $text )
) {
- # Bug 529: if the template begins with a table or block-level
+ # T2529: if the template begins with a table or block-level
# element, it should be treated as beginning a new line.
# This behavior is somewhat controversial.
$text = "\n" . $text;
if ( is_string( $text ) && !$this->incrementIncludeSize( 'post-expand', strlen( $text ) ) ) {
# Error, oversize inclusion
if ( $titleText !== false ) {
- # Make a working, properly escaped link if possible (bug 23588)
+ # Make a working, properly escaped link if possible (T25588)
$text = "[[:$titleText]]";
} else {
# This will probably not be a working link, but at least it may
) {
$this->addTrackingCategory( 'hidden-category-category' );
}
- # (bug 8068) Allow control over whether robots index a page.
- # @todo FIXME: Bug 14899: __INDEX__ always overrides __NOINDEX__ here! This
- # is not desirable, the last one on the page should win.
+ # (T10068) Allow control over whether robots index a page.
+ # __INDEX__ always overrides __NOINDEX__, see T16899
if ( isset( $this->mDoubleUnderscores['noindex'] ) && $this->mTitle->canUseNoindex() ) {
$this->mOutput->setIndexPolicy( 'noindex' );
$this->addTrackingCategory( 'noindex-category' );
# Strip out HTML (first regex removes any tag not allowed)
# Allowed tags are:
- # * <sup> and <sub> (bug 8393)
- # * <i> (bug 26375)
+ # * <sup> and <sub> (T10393)
+ # * <i> (T28375)
# * <b> (r105284)
- # * <bdi> (bug 72884)
- # * <span dir="rtl"> and <span dir="ltr"> (bug 35167)
+ # * <bdi> (T74884)
+ # * <span dir="rtl"> and <span dir="ltr"> (T37167)
# * <s> and <strike> (T35715)
# We strip any parameter from accepted tags (second regex), except dir="rtl|ltr" from <span>,
# to allow setting directionality in toc items.
'noninitial' );
}
- # HTML names must be case-insensitively unique (bug 10721).
+ # HTML names must be case-insensitively unique (T12721).
# This does not apply to Unicode characters per
# https://www.w3.org/TR/html5/infrastructure.html#case-sensitivity-and-string-comparison
# @todo FIXME: We may be changing them depending on the current locale.
# the database, we use $wgContLang here in order to give
# everyone the same signature and use the default one rather
# than the one selected in each user's preferences.
- # (see also bug 12815)
+ # (see also T14815)
$ts = $this->mOptions->getTimestamp();
$timestamp = MWTimestamp::getLocalInstance( $ts );
$ts = $timestamp->format( 'YmdHis' );
$validated = true;
}
}
- # else no validation -- bug 13436
+ # else no validation -- T15436
} else {
if ( $type === 'handler' ) {
# Validate handler parameter
* was derived during a template inclusion parse, in other words this is a template
* section edit link. If no flags are given, it was an ordinary section edit link.
* This flag is required to avoid a section numbering mismatch when a section is
- * enclosed by "<includeonly>" (bug 6563).
+ * enclosed by "<includeonly>" (T8563).
*
* The section number 0 pulls the text before the first heading; other numbers will
* pull the given section along with its lower-level subsections. If the section is
return $parsedWidthParam;
}
$m = [];
- # (bug 13500) In both cases (width/height and width only),
+ # (T15500) In both cases (width/height and width only),
# permit trailing "px" for backward compatibility.
if ( preg_match( '/^([0-9]*)x([0-9]*)\s*(?:px)?\s*$/', $value, $m ) ) {
$width = intval( $m[1] );
$this->namespaceNames = self::$dataCache->getItem( $this->mCode, 'namespaceNames' );
$validNamespaces = MWNamespace::getCanonicalNamespaces();
+ /** @suppress PhanTypeInvalidLeftOperand */
$this->namespaceNames = $wgExtraNamespaces + $this->namespaceNames + $validNamespaces;
$this->namespaceNames[NS_PROJECT] = $wgMetaNamespace;
--- /dev/null
+-- @since 1.29
+ALTER TABLE /*$wgDBprefix*/externallinks ADD COLUMN el_index_60 varbinary(60) NOT NULL DEFAULT '';
+CREATE INDEX /*i*/el_index_60 ON /*_*/externallinks (el_index_60, el_id);
+CREATE INDEX /*i*/el_from_index_60 ON /*_*/externallinks (el_from, el_index_60, el_id);
-- which allows for fast searching for all pages under example.com with the
-- clause:
-- WHERE el_index LIKE 'http://com.example.%'
- el_index nvarchar(450) NOT NULL
+ el_index nvarchar(450) NOT NULL,
+
+ -- This is el_index truncated to 60 bytes to allow for sortable queries that
+ -- aren't supported by a partial index.
+ -- @todo Drop the default once this is deployed everywhere and code is populating it.
+ el_index_60 varbinary(60) NOT NULL default ''
);
CREATE INDEX /*i*/el_from ON /*_*/externallinks (el_from);
CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index);
+CREATE INDEX /*i*/el_index_60 ON /*_*/externallinks (el_index_60, el_id);
+CREATE INDEX /*i*/el_from_index_60 ON /*_*/externallinks (el_from, el_index_60, el_id);
-- el_to index intentionally not added; we cannot index nvarchar(max) columns,
-- but we also cannot restrict el_to to a smaller column size as the external
-- link may be larger.
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.externallinks ADD el_index_60 VARBINARY(60) NOT NULL DEFAULT '';
+CREATE INDEX &mw_prefix.externallinks_i04 ON &mw_prefix.externallinks (el_index_60, el_id);
+CREATE INDEX &mw_prefix.externallinks_i05 ON &mw_prefix.externallinks (el_from, el_index_60, el_id);
el_id NUMBER NOT NULL,
el_from NUMBER NOT NULL,
el_to VARCHAR2(2048) NOT NULL,
- el_index VARCHAR2(2048) NOT NULL
+ el_index VARCHAR2(2048) NOT NULL,
+ el_index_60 VARBINARY(60) NOT NULL DEFAULT ''
);
ALTER TABLE &mw_prefix.externallinks ADD CONSTRAINT &mw_prefix.externallinks_pk PRIMARY KEY (el_id);
ALTER TABLE &mw_prefix.externallinks ADD CONSTRAINT &mw_prefix.externallinks_fk1 FOREIGN KEY (el_from) REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX &mw_prefix.externallinks_i01 ON &mw_prefix.externallinks (el_from, el_to);
CREATE INDEX &mw_prefix.externallinks_i02 ON &mw_prefix.externallinks (el_to, el_from);
CREATE INDEX &mw_prefix.externallinks_i03 ON &mw_prefix.externallinks (el_index);
+CREATE INDEX &mw_prefix.externallinks_i04 ON &mw_prefix.externallinks (el_index_60, el_id);
+CREATE INDEX &mw_prefix.externallinks_i05 ON &mw_prefix.externallinks (el_from, el_index_60, el_id);
CREATE TABLE &mw_prefix.langlinks (
ll_from NUMBER NOT NULL,
CREATE SEQUENCE externallinks_el_id_seq;
CREATE TABLE externallinks (
- el_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('externallinks_el_id_seq'),
- el_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
- el_to TEXT NOT NULL,
- el_index TEXT NOT NULL
+ el_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('externallinks_el_id_seq'),
+ el_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ el_to TEXT NOT NULL,
+ el_index TEXT NOT NULL,
+ el_index_60 BYTEA NOT NULL DEFAULT ''
);
CREATE INDEX externallinks_from_to ON externallinks (el_from,el_to);
CREATE INDEX externallinks_index ON externallinks (el_index);
+CREATE INDEX el_index_60 ON externallinks (el_index_60, el_id);
+CREATE INDEX el_from_index_60 ON externallinks (el_from, el_index_60, el_id);
CREATE TABLE langlinks (
ll_from INTEGER NOT NULL REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
-- which allows for fast searching for all pages under example.com with the
-- clause:
-- WHERE el_index LIKE 'http://com.example.%'
- el_index blob NOT NULL
+ el_index blob NOT NULL,
+
+ -- This is el_index truncated to 60 bytes to allow for sortable queries that
+ -- aren't supported by a partial index.
+ -- @todo Drop the default once this is deployed everywhere and code is populating it.
+ el_index_60 varbinary(60) NOT NULL default ''
) /*$wgDBTableOptions*/;
CREATE INDEX /*i*/el_from ON /*_*/externallinks (el_from, el_to(40));
CREATE INDEX /*i*/el_to ON /*_*/externallinks (el_to(60), el_from);
CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index(60));
+CREATE INDEX /*i*/el_index_60 ON /*_*/externallinks (el_index_60, el_id);
+CREATE INDEX /*i*/el_from_index_60 ON /*_*/externallinks (el_from, el_index_60, el_id);
--
-- Track interlanguage links
table.wikitable > tr > td,
table.wikitable > * > tr > th,
table.wikitable > * > tr > td {
- border: 1px solid #aaa;
+ border: 1px solid #a2a9b1;
padding: 0.2em 0.4em;
}
php7.0 $PHAN \
--project-root-directory "$ROOT" \
--config-file "$ROOT/tests/phan/config.php" \
- --output "$ROOT/tests/phan/issues/issues-${REV}" \
+ --output "$RUN" \
"${@}"
+
+cat "${RUN}" | php "$ROOT/tests/phan/bin/postprocess-phan.php" "${@}" > /tmp/phan.$$
EXIT_CODE="$?"
+mv /tmp/phan.$$ "${RUN}"
# Re-link the latest file
rm -f "${ISSUES}/latest"
--- /dev/null
+<?php
+
+abstract class Suppressor {
+ /**
+ * @param string $input
+ * @return bool do errors remain
+ */
+ abstract public function suppress( $input );
+
+ /**
+ * @param string[] $source
+ * @param string $type
+ * @param int $lineno
+ * @return bool
+ */
+ protected function isSuppressed( array $source, $type, $lineno ) {
+ return $lineno > 0 && preg_match(
+ "|/\*\* @suppress {$type} |",
+ $source[$lineno - 1]
+ );
+ }
+}
+
+class TextSuppressor extends Suppressor {
+ /**
+ * @param string $input
+ * @return bool do errors remain
+ */
+ public function suppress( $input ) {
+ $hasErrors = false;
+ $errors = [];
+ foreach ( explode( "\n", $input ) as $error ) {
+ if ( empty( $error ) ) {
+ continue;
+ }
+ if ( !preg_match( '/^(.*):(\d+) (Phan\w+) (.*)$/', $error, $matches ) ) {
+ echo "Failed to parse line: $error\n";
+ continue;
+ }
+ list( $source, $file, $lineno, $type, $message ) = $matches;
+ $errors[$file][] = [
+ 'orig' => $error,
+ // convert from 1 indexed to 0 indexed
+ 'lineno' => $lineno - 1,
+ 'type' => $type,
+ ];
+ }
+ foreach ( $errors as $file => $fileErrors ) {
+ $source = file( $file );
+ foreach ( $fileErrors as $error ) {
+ if ( !$this->isSuppressed( $source, $error['type'], $error['lineno'] ) ) {
+ echo $error['orig'], "\n";
+ $hasErrors = true;
+ }
+ }
+ }
+
+ return $hasErrors;
+ }
+}
+
+class CheckStyleSuppressor extends Suppressor {
+ /**
+ * @param string $input
+ * @return bool True do errors remain
+ */
+ public function suppress( $input ) {
+ $dom = new DOMDocument();
+ $dom->loadXML( $input );
+ $hasErrors = false;
+ // DOMNodeList's are "live", convert to an array so it works as expected
+ $files = [];
+ foreach ( $dom->getElementsByTagName( 'file' ) as $file ) {
+ $files[] = $file;
+ }
+ foreach ( $files as $file ) {
+ $errors = [];
+ foreach ( $file->getElementsByTagName( 'error' ) as $error ) {
+ $errors[] = $error;
+ }
+ $source = file( $file->getAttribute( 'name' ) );
+ $fileHasErrors = false;
+ foreach ( $errors as $error ) {
+ $lineno = $error->getAttribute( 'line' ) - 1;
+ $type = $error->getAttribute( 'source' );
+ if ( $this->isSuppressed( $source, $type, $lineno ) ) {
+ $error->parentNode->removeChild( $error );
+ } else {
+ $fileHasErrors = true;
+ $hasErrors = true;
+ }
+ }
+ if ( !$fileHasErrors ) {
+ $file->parentNode->removeChild( $file );
+ }
+ }
+ echo $dom->saveXML();
+
+ return $hasErrors;
+ }
+}
+
+class NoopSuppressor extends Suppressor {
+ private $mode;
+
+ public function __construct( $mode ) {
+ $this->mode = $mode;
+ }
+ public function suppress( $input ) {
+ echo "Unsupported output mode: {$this->mode}\n$input";
+ return true;
+ }
+}
+
+$opt = getopt( "m:", [ "output-mode:" ] );
+// if provided multiple times getopt returns an array
+if ( isset( $opt['m'] ) ) {
+ $mode = $opt['m'];
+} elseif ( isset( $mode['output-mode'] ) ) {
+ $mode = $opt['output-mode'];
+} else {
+ $mode = 'text';
+}
+if ( is_array( $mode ) ) {
+ // If an option is passed multiple times getopt returns an
+ // array. Just take the last one.
+ $mode = end( $mode );
+}
+
+switch ( $mode ) {
+case 'text':
+ $suppressor = new TextSuppressor();
+ break;
+case 'checkstyle':
+ $suppressor = new CheckStyleSuppressor();
+ break;
+default:
+ $suppressor = new NoopSuppressor( $mode );
+}
+
+$input = file_get_contents( 'php://stdin' );
+$hasErrors = $suppressor->suppress( $input );
+
+if ( $hasErrors ) {
+ exit( 1 );
+}
"PhanTypeArraySuspicious",
// approximate error count: 4
"PhanTypeComparisonFromArray",
- // approximate error count: 1
- "PhanTypeInvalidLeftOperand",
// approximate error count: 3
"PhanTypeInvalidRightOperand",
// approximate error count: 563
/**
* Make sure MediaWikiTestCase extending classes have called their
* parent setUp method
+ *
+ * With strict coverage activated in PHP_CodeCoverage, this test would be
+ * marked as risky without the following annotation (T152923).
+ * @coversNothing
*/
final public function testMediaWikiTestCaseParentSetupCalled() {
$this->assertArrayHasKey( 'setUp', $this->called,
[],
[],
],
+ [
+ [],
+ [ [] ],
+ ],
[
[ 'foo' ],
[ 'foo' ],
[ [ 'baz', 'foo' ] ],
],
[
- [ 'baz', 'foo' ],
+ [ Message::rawParam( 'baz' ) ],
+ [ Message::rawParam( 'baz' ) ],
+ ],
+ [
+ [ Message::rawParam( 'baz' ), 'foo' ],
+ [ Message::rawParam( 'baz' ), 'foo' ],
+ ],
+ [
+ [ Message::rawParam( 'baz' ) ],
+ [ [ Message::rawParam( 'baz' ) ] ],
+ ],
+ [
+ [ Message::rawParam( 'baz' ), 'foo' ],
+ [ [ Message::rawParam( 'baz' ), 'foo' ] ],
+ ],
+
+ // Test handling of erroneous input, to detect if it changes
+ [
+ [ [ 'baz', 'foo' ], 'hhh' ],
[ [ 'baz', 'foo' ], 'hhh' ],
],
[
- [ 'baz', 'foo' ],
+ [ [ 'baz', 'foo' ], 'hhh', [ 'ahahahahha' ] ],
[ [ 'baz', 'foo' ], 'hhh', [ 'ahahahahha' ] ],
],
[
- [ 'baz', 'foo' ],
+ [ [ 'baz', 'foo' ], [ 'ahahahahha' ] ],
[ [ 'baz', 'foo' ], [ 'ahahahahha' ] ],
],
[
- [ 'baz' ],
+ [ [ 'baz' ], [ 'ahahahahha' ] ],
[ [ 'baz' ], [ 'ahahahahha' ] ],
],
];