This allows us to remove many suppressions for phan false positives.
Bug: T231636
Depends-On: I82a279e1f7b0fdefd3bb712e46c7d0665429d065
Change-Id: I5c251e9584a1ae9fb1577afcafb5001e0dcd41c7
'includes/libs/jsminplus.php',
];
+// NOTE: If you're facing an issue which you cannot easily fix, DO NOT add it here. Suppress it
+// either in-line with @phan-suppress-next-line and similar, at block-level (via @suppress), or at
+// file-level (with @phan-file-suppress), so that it stays enabled for the rest of the codebase.
$cfg['suppress_issue_types'] = array_merge( $cfg['suppress_issue_types'], [
// approximate error count: 19
"PhanParamReqAfterOpt", // False positives with nullables (phan issue #3159). Use real nullables
// approximate error count: 110
"PhanParamTooMany", // False positives with variargs. Unsuppress after dropping HHVM
- // approximate error count: 60
+ // approximate error count: 45
"PhanTypeMismatchArgument",
- // approximate error count: 752
+ // approximate error count: 693
"PhanUndeclaredProperty",
] );
+// This helps a lot in discovering bad code, but unfortunately it will always fail for
+// hooks + pass by reference, see phan issue #2943.
+// @todo Enable when the issue above is resolved and we update our config!
+$cfg['redundant_condition_detection'] = false;
+
$cfg['ignore_undeclared_variables_in_global_scope'] = true;
// @todo It'd be great if we could just make phan read these from DefaultSettings, to avoid
// duplicating the types.
'wgWANObjectCaches' => 'array[]',
'wgLocalInterwikis' => 'string[]',
'wgDebugLogGroups' => 'string|false|array{destination:string,sample?:int,level:int}',
+ 'wgCookiePrefix' => 'string|false',
+ 'wgOut' => 'OutputPage',
+ 'wgExtraNamespaces' => 'string[]',
] );
return $cfg;
"wikimedia/avro": "1.8.0",
"wikimedia/testing-access-wrapper": "~1.0",
"wmde/hamcrest-html-matchers": "^0.1.0",
- "mediawiki/mediawiki-phan-config": "0.6.1",
+ "mediawiki/mediawiki-phan-config": "0.7.1",
"symfony/yaml": "3.4.28",
"johnkary/phpunit-speedtrap": "^1.0 | ^2.0"
},
}
$includeStderr = isset( $options['duplicateStderr'] ) && $options['duplicateStderr'];
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
$profileMethod = $options['profileMethod'] ?? wfGetCaller();
try {
// Give site config file a chance to run the script in a wrapper.
// The caller may likely want to call wfBasename() on $script.
Hooks::run( 'wfShellWikiCmd', [ &$script, &$parameters, &$options ] );
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
$cmd = [ $options['php'] ?? $wgPhpCli ];
if ( isset( $options['wrapper'] ) ) {
$cmd[] = $options['wrapper'];
$result = unpack( $format, $data );
Wikimedia\restoreWarnings();
- // @phan-suppress-next-line PhanTypeComparisonFromArray Phan issue #3160
if ( $result === false ) {
// If it cannot extract the packed data.
throw new MWException( "unpack could not unpack binary data" );
throw new InvalidArgumentException( 'Mismatching wiki ID ' . $rev->getWikiId() );
}
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
$audience = $hints['audience']
?? ( $forUser ? RevisionRecord::FOR_THIS_USER : RevisionRecord::FOR_PUBLIC );
$options = ParserOptions::newCanonical( $forUser ?: 'canonical' );
}
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
$useMaster = $hints['use-master'] ?? false;
$dbIndex = $useMaster
private function preCacheMessages() {
// Precache various messages
if ( !isset( $this->message ) ) {
+ $this->message = [];
$msgs = [ 'cur', 'last', 'pipe-separator' ];
foreach ( $msgs as $msg ) {
$this->message[$msg] = $this->msg( $msg )->escaped();
if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
$parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
$dom = $parser->preprocessToDom( $params['text'] );
+ // @phan-suppress-next-line PhanUndeclaredMethodInCallable
if ( is_callable( [ $dom, 'saveXML' ] ) ) {
// @phan-suppress-next-line PhanUndeclaredMethod
$xml = $dom->saveXML();
* @return string
*/
protected function encodeRequestLogValue( $s ) {
- static $table;
+ static $table = [];
if ( !$table ) {
$chars = ';@$!*(),/:';
$numChars = strlen( $chars );
];
}
+ /**
+ * @inheritDoc
+ * @phan-param array{nolead?:bool,headerlevel?:int,tocnumber?:int[]} $options
+ */
public function modifyHelp( array &$help, array $options, array &$tocData ) {
// Wish PHP had an "array_insert_before". Instead, we have to manually
// reindex the array to get 'permissions' in the right place.
/**
* @param ApiPageSet $resultPageSet
* @return void
- * @suppress PhanTypeInvalidDimOffset
*/
private function run( $resultPageSet = null ) {
$this->params = $this->extractRequestParams( false );
Parser::OT_PREPROCESS
);
$dom = $parser->preprocessToDom( $t );
+ // @phan-suppress-next-line PhanUndeclaredMethodInCallable
if ( is_callable( [ $dom, 'saveXML' ] ) ) {
// @phan-suppress-next-line PhanUndeclaredMethod
$xml = $dom->saveXML();
* @return AuthenticationRequest
*/
public static function __set_state( $data ) {
- // @phan-suppress-next-line PhanTypeInstantiateAbstract
+ // @phan-suppress-next-line PhanTypeInstantiateAbstractStatic
$ret = new static();
foreach ( $data as $k => $v ) {
$ret->$k = $v;
* @inheritDoc
*/
public static function newFromRow( \stdClass $row ) {
- // @phan-suppress-next-line PhanTypeInstantiateAbstract
+ // @phan-suppress-next-line PhanTypeInstantiateAbstractStatic
return new static( $row->ir_ipb_id, $row->ir_value );
}
*/
private function preCacheMessages() {
if ( !isset( $this->message ) ) {
+ $this->message = [];
foreach ( [
'cur', 'diff', 'hist', 'enhancedrc-history', 'last', 'blocklink', 'history',
'semicolon-separator', 'pipe-separator' ] as $msg
if ( is_array( $etcdResponse['config'] ) ) {
// Avoid having all servers expire cache keys at the same time
$expiry = microtime( true ) + $this->baseCacheTTL;
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
$expiry += mt_rand( 0, 1e6 ) / 1e6 * $this->skewCacheTTL;
$data = [
'config' => $etcdResponse['config'],
* @param Revision|Content $undoafter Must be from an earlier revision than $undo
* @param bool $undoIsLatest Set true if $undo is from the current revision (since 1.32)
*
- * @return mixed Content on success, false on failure
+ * @return Content|false Content on success, false on failure
*/
public function getUndoContent( $current, $undo, $undoafter, $undoIsLatest = false ) {
Assert::parameterType( Revision::class . '|' . Content::class, $current, '$current' );
*/
$max = min( $this->m, $this->n );
for ( $forwardBound = 0; $forwardBound < $max
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
&& $this->from[$forwardBound] === $this->to[$forwardBound];
++$forwardBound
) {
*/
private $progress;
+ /**
+ * @param DumpOutput &$sink
+ * @param BackupDumper &$progress
+ */
function __construct( &$sink, &$progress ) {
parent::__construct( $sink );
$this->progress = $progress;
* be found.
* latest: If true, load from the latest available data into File objects
* @phan-param array{time?:mixed,ignoreRedirect?:bool,private?:bool,latest?:bool} $options
- * @suppress PhanTypeInvalidDimOffset
* @return File|bool False if title is not found
*/
function findFile( $title, $options = [] ) {
array_shift( $urls ); // don't purge directory
// Give media handler a chance to filter the file purge list
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
if ( !empty( $options['forThumbRefresh'] ) ) {
$handler = $this->getHandler();
if ( $handler ) {
* The old name of autocomplete-data[-messages] was autocomplete[-messages] which is still
* recognized but deprecated since MediaWiki 1.29 since it conflicts with how autocomplete is
* used in HTMLTextField.
- *
- * @phan-file-suppress PhanTypeMismatchProperty This is doing weird things with mClass
*/
class HTMLAutoCompleteSelectField extends HTMLTextField {
protected $autocompleteData = [];
$ret = $select->getHTML() . "<br />\n";
- // @phan-suppress-next-line PhanTypeMismatchDimEmpty
$this->mClass[] = 'mw-htmlform-hide-if';
}
}
}
- // @phan-suppress-next-line PhanTypeMismatchDimEmpty
$this->mClass[] = 'mw-htmlform-autocomplete';
$ret .= parent::getInputHTML( $valInSelect ? '' : $value );
$this->mClass = $oldClass;
$this->url = wfExpandUrl( $url, PROTO_HTTP );
$this->parsedUrl = wfParseUrl( $this->url );
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
$this->logger = $options['logger'] ?? new NullLogger();
if ( !$this->parsedUrl || !Http::isValidURI( $this->url ) ) {
}
parent::__construct( $baseIterator );
$this->vCallback = $vCallback;
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
$this->aCallback = $options['accept'] ?? null;
}
/** @var array List of path or (path,stat array) entries */
protected $bufferIter = [];
- /** @var string List items *after* this path */
+ /** @var string|null List items *after* this path */
protected $bufferAfter = null;
/** @var int */
$this->pos = 0;
$this->bufferAfter = null;
$this->bufferIter = $this->pageFromList(
+ // @phan-suppress-next-line PhanTypeMismatchArgumentPropertyReferenceReal
$this->container, $this->dir, $this->bufferAfter, self::PAGE_SIZE, $this->params
); // updates $this->bufferAfter
}
$name = strtolower( $name );
$value = trim( $value );
if ( isset( $req['response']['headers'][$name] ) ) {
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
$req['response']['headers'][$name] .= ', ' . $value;
} else {
$req['response']['headers'][$name] = $value;
* @codingStandardsIgnoreStart
* @phan-param array{logger?:Psr\Log\LoggerInterface,asyncHandler?:callable,keyspace?:string,reportDupes?:bool,syncTimeout?:int,segmentationSize?:int,segmentedValueMaxSize?:int,maxKeys?:int} $params
* @codingStandardsIgnoreEnd
- * @suppress PhanTypeInvalidDimOffset
*/
function __construct( $params = [] ) {
$params['segmentationSize'] = $params['segmentationSize'] ?? INF;
* @note Options added in 1.33: creating
* @note Options added in 1.34: version, walltime
* @return bool Success
- * @suppress PhanTypeInvalidDimOffset
*/
final public function set( $key, $value, $ttl = self::TTL_INDEFINITE, array $opts = [] ) {
$now = $this->getCurrentTime();
* @note Options added in 1.31: staleTTL, graceTTL
* @note Options added in 1.33: touchedCallback
* @note Callable type hints are not used to avoid class-autoloading
- * @suppress PhanTypeInvalidDimOffset
*/
final public function getWithSetCallback( $key, $ttl, $callback, array $opts = [] ) {
$version = $opts['version'] ?? null;
$this->setInterimValue( $key, $value, $lockTSE, $version, $walltime );
} else {
$finalSetOpts = [
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
'since' => $setOpts['since'] ?? $preCallbackTime,
'version' => $version,
'staleTTL' => $staleTTL,
$chance = ( 1 - $curTTL / $lowTTL );
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
return mt_rand( 1, 1e9 ) <= 1e9 * $chance;
}
// Ramp up $chance from 0 to its nominal value over RAMPUP_TTL seconds to avoid stampedes
$chance *= ( $timeOld <= self::$RAMPUP_TTL ) ? $timeOld / self::$RAMPUP_TTL : 1;
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
return mt_rand( 1, 1e9 ) <= 1e9 * $chance;
}
$key = $this->getCacheKey( $serverIndexes );
# Randomize TTLs to reduce stampedes (4.0 - 5.0 sec)
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
$ttl = mt_rand( 4e6, 5e6 ) / 1e6;
# Keep keys around longer as fallbacks
$staleTTL = 60;
* All metadata related, since both JPEG and TIFF support Exif.
*
* @ingroup Media
- * @phan-file-suppress PhanUndeclaredConstant Phan doesn't read constants in MediaHandler
- * when accessed via self::
*/
class ExifBitmapHandler extends BitmapHandler {
const BROKEN_FILE = '-1'; // error extracting metadata
* @param bool $isMain
* @return mixed|string
* @private
- * @suppress PhanTypeInvalidDimOffset
*/
public function formatHeadings( $text, $origText, $isMain = true ) {
# Inhibit editsection links if requested in the page
Hooks::run( 'ParserMakeImageParams', [ $title, $file, &$params, $this ] );
# Linker does the rest
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
$time = $options['time'] ?? false;
$ret = Linker::makeImageLink( $this, $title, $file, $params['frame'], $params['handler'],
$time, $descQuery, $this->mOptions->getThumbSize() );
if ( !is_null( $this->parsers ) ) {
return;
}
+ $this->parsers = [];
if ( isset( $this->conf['shortOutput'] ) ) {
$this->shortOutput = $this->conf['shortOutput'];
// @codeCoverageIgnoreStart
// T109544 - If a feed formatter returns null, this will otherwise cause an
// error in at least RedisPubSubFeedEngine. Not sure best to handle this.
- // @phan-suppress-next-line PhanTypeMismatchReturn
return;
// @codeCoverageIgnoreEnd
}
$idx = -1;
foreach ( $grpModules as $name => $module ) {
$shouldEmbed = $module->shouldEmbedModule( $context );
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
if ( !$moduleSets || $moduleSets[$idx][0] !== $shouldEmbed ) {
$moduleSets[++$idx] = [ $shouldEmbed, [] ];
}
$dataPath->getRemoteBasePath()
);
} else {
- // @phan-suppress-next-line PhanTypeSuspiciousStringExpression
$path = dirname( $dataPath ) . '/' . $path;
}
};
"$provider returned empty session info with id flagged unsafe"
);
}
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
$compare = $infos ? SessionInfo::compare( $infos[0], $info ) : -1;
if ( $compare > 0 ) {
continue;
// Give site config file a chance to run the script in a wrapper.
// The caller may likely want to call wfBasename() on $script.
Hooks::run( 'wfShellWikiCmd', [ &$script, &$parameters, &$options ] );
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
$cmd = [ $options['php'] ?? $wgPhpCli ];
if ( isset( $options['wrapper'] ) ) {
$cmd[] = $options['wrapper'];
if ( isset( $item['itemtitle'] ) ) {
$attrs['title'] = $item['itemtitle'];
}
- // @phan-suppress-next-line PhanTypeInvalidDimOffset
return Html::rawElement( $options['tag'] ?? 'li', $attrs, $html );
}
*/
private function getExceptionList() {
if ( $this->exceptionList === null ) {
+ $this->exceptionList = [];
$exList = $this->msg( 'uncategorized-categories-exceptionlist' )
->inContentLanguage()->plain();
$proposedTitles = explode( "\n", $exList );
* @param string $name
* @param string $value
* @return string
- * @suppress PhanTypeArraySuspiciousNullable,PhanTypeArraySuspicious
+ * @suppress PhanTypeArraySuspicious
*/
function formatValue( $name, $value ) {
static $msg = null;
* Returns array of all defined namespaces with their canonical
* (English) names.
*
- * @return array
+ * @return string[]
*/
public function getCanonicalNamespaces() {
if ( $this->canonicalNamespaces === null ) {
*/
public function getValidNamespaces() {
if ( is_null( $this->validNamespaces ) ) {
+ $this->validNamespaces = [];
foreach ( array_keys( $this->getCanonicalNamespaces() ) as $ns ) {
if ( $ns >= 0 ) {
$this->validNamespaces[] = $ns;
return $this->$name;
} else {
wfLogWarning( 'tried to get non-visible property' );
- return null;
+ $null = null;
+ return $null;
}
}
}
# Sometimes a language will be localised but not actually exist on this wiki.
- // @phan-suppress-next-line PhanTypeMismatchForeach
foreach ( $this->namespaceNames as $key => $text ) {
if ( !isset( $validNamespaces[$key] ) ) {
unset( $this->namespaceNames[$key] );
# The above mixing may leave namespaces out of canonical order.
# Re-order by namespace ID number...
- // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
ksort( $this->namespaceNames );
Hooks::run( 'LanguageGetNamespaces', [ &$this->namespaceNames ] );
$fallbackChain = array_reverse( $fallbackChain );
foreach ( $fallbackChain as $code ) {
if ( isset( $newWords[$code] ) ) {
- // @phan-suppress-next-line PhanTypeMismatchProperty
$this->mMagicExtensions = $newWords[$code] + $this->mMagicExtensions;
}
}
// Const for getStdin()
const STDIN_ALL = 'all';
- // Array of desired/allowed params
+ /**
+ * Array of desired/allowed params
+ * @var array[]
+ * @phan-var array<string,array{desc:string,require:bool,withArg:string,shortName:string,multiOccurrence:bool}>
+ */
protected $mParams = [];
// Array of mapping short parameters to long ones
*/
protected $mBatchSize = null;
- // Generic options added by addDefaultParams()
+ /**
+ * Generic options added by addDefaultParams()
+ * @var array[]
+ * @phan-var array<string,array{desc:string,require:bool,withArg:string,shortName:string,multiOccurrence:bool}>
+ */
private $mGenericParameters = [];
- // Generic options which might or not be supported by the script
+ /**
+ * Generic options which might or not be supported by the script
+ * @var array[]
+ * @phan-var array<string,array{desc:string,require:bool,withArg:string,shortName:string,multiOccurrence:bool}>
+ */
private $mDependantParameters = [];
/**
$min = $times[0];
$max = end( $times );
if ( $n % 2 ) {
+ // @phan-suppress-next-line PhanTypeMismatchDimFetch
$median = $times[ ( $n - 1 ) / 2 ];
} else {
$median = ( $times[$n / 2] + $times[$n / 2 - 1] ) / 2;
/**
* @param string $realName
* @param array[] $value
- * @suppress PhanTypeInvalidDimOffset
*/
protected function handleResourceModules( $realName, $value ) {
$defaults = [];
# Protect the file
$this->output( "\nWaiting for replica DBs...\n" );
// Wait for replica DBs.
- sleep( 2.0 ); # Why this sleep?
+ sleep( 2 ); # Why this sleep?
wfWaitForSlaves();
$this->output( "\nSetting image restrictions ... " );
"Show some statistics on the blob_orphans table, created with trackBlobs.php" );
}
- protected function &getDB( $cluster, $groups = [], $wiki = false ) {
+ protected function getDB( $cluster, $groups = [], $wiki = false ) {
$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
$lb = $lbFactory->getExternalLB( $cluster );