diff --git a/composer.json b/composer.json index 649acf1253a..02a13f9bf64 100644 --- a/composer.json +++ b/composer.json @@ -88,7 +88,7 @@ "hamcrest/hamcrest-php": "^2.0", "johnkary/phpunit-speedtrap": "^4.0", "mediawiki/mediawiki-codesniffer": "39.0.0", - "mediawiki/mediawiki-phan-config": "0.11.1", + "mediawiki/mediawiki-phan-config": "0.12.0", "nikic/php-parser": "^4.10.2", "php-parallel-lint/php-console-highlighter": "1.0.0", "php-parallel-lint/php-parallel-lint": "1.3.2", diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 4101eaecf02..d4d6bf7af35 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -1938,7 +1938,6 @@ function wfGetDB( $db, $groups = [], $wiki = false ) { function wfScript( $script = 'index' ) { global $wgScriptPath, $wgScript, $wgLoadScript; if ( $script === 'index' ) { - // @phan-suppress-next-line PhanPossiblyUndeclaredVariable False positive return $wgScript; } elseif ( $script === 'load' ) { return $wgLoadScript; diff --git a/includes/OutputPage.php b/includes/OutputPage.php index 3b012d833ea..dd47d9d6fe6 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -3118,6 +3118,7 @@ class OutputPage extends ContextSource { $text .= ''; } else { $text .= "
"; } diff --git a/includes/Rest/Handler/ParsoidHandler.php b/includes/Rest/Handler/ParsoidHandler.php index 0a7833588ee..ccde74a6b71 100644 --- a/includes/Rest/Handler/ParsoidHandler.php +++ b/includes/Rest/Handler/ParsoidHandler.php @@ -794,7 +794,10 @@ abstract class ParsoidHandler extends Handler { ParsoidFormatHelper::setContentType( $response, ParsoidFormatHelper::FORMAT_HTML, $attribs['envOptions']['outputContentVersion'] ); $response->getBody()->write( $out ); + // @phan-suppress-next-next-line PhanTypeArraySuspiciousNullable $headers can't be null after the + // method call, but the docblock of wikitext2html doesn't say that. $response->setHeader( 'Content-Language', $headers['content-language'] ); + // @phan-suppress-next-line PhanTypeArraySuspiciousNullable Same. $response->addHeader( 'Vary', $headers['vary'] ); } diff --git a/includes/Title.php b/includes/Title.php index f2e1a28e57c..51a980c1882 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -804,7 +804,6 @@ class Title implements LinkTarget, PageIdentity, IDBAccessObject { $r0 = $d0; } // Do the output - // @phan-suppress-next-line PhanPluginRedundantAssignmentInLoop Confusing, $r1 is set later if ( $x0 !== '' && $x1 === '-' && $x2 !== '' ) { // Range if ( $ord2 > $ord0 ) { @@ -821,6 +820,7 @@ class Title implements LinkTarget, PageIdentity, IDBAccessObject { $out .= "$r2-$r0"; } // Reset state to the initial value + // @phan-suppress-next-line PhanPluginRedundantAssignmentInLoop $x0 = $x1 = $d0 = $d1 = $r0 = $r1 = ''; } elseif ( $ord2 < 0x80 ) { // ASCII character @@ -2271,7 +2271,6 @@ class Title implements LinkTarget, PageIdentity, IDBAccessObject { $url = false; $matches = []; - // @phan-suppress-next-line PhanPossiblyUndeclaredVariable False positive $articlePaths = PathRouter::getActionPaths( $wgActionPaths, $wgArticlePath ); if ( $articlePaths @@ -2310,7 +2309,6 @@ class Title implements LinkTarget, PageIdentity, IDBAccessObject { if ( $query == '-' ) { $query = ''; } - // @phan-suppress-next-line PhanPossiblyUndeclaredVariable False positive $url = "{$wgScript}?title={$dbkey}&{$query}"; } } @@ -2340,7 +2338,6 @@ class Title implements LinkTarget, PageIdentity, IDBAccessObject { */ public function getLinkURL( $query = '', $query2 = false, $proto = false ) { if ( $this->isExternal() || $proto !== false ) { - // @phan-suppress-next-line PhanTypeMismatchArgument $ret = $this->getFullURL( $query, $query2, $proto ); } elseif ( $this->getPrefixedText() === '' && $this->hasFragment() ) { $ret = $this->getFragmentForURL(); diff --git a/includes/WebRequest.php b/includes/WebRequest.php index 24a386ecd81..8819293983f 100644 --- a/includes/WebRequest.php +++ b/includes/WebRequest.php @@ -166,7 +166,6 @@ class WebRequest { $path = $a['path'] ?? ''; global $wgScript; - // @phan-suppress-next-line PhanPossiblyUndeclaredVariable False positive if ( $path == $wgScript && $want !== 'all' ) { // Script inside a rewrite path? // Abort to keep from breaking... @@ -176,7 +175,6 @@ class WebRequest { $router = new PathRouter; // Raw PATH_INFO style - // @phan-suppress-next-line PhanPossiblyUndeclaredVariable False positive $router->add( "$wgScript/$1" ); global $wgArticlePath; diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php index d62955dd214..fc0b00812a5 100644 --- a/includes/api/ApiBase.php +++ b/includes/api/ApiBase.php @@ -1465,7 +1465,6 @@ abstract class ApiBase extends ContextSource { * @return never */ public function dieWithException( Throwable $exception, array $options = [] ) { - // @phan-suppress-previous-line PhanTypeMissingReturn $this->dieWithError( // @phan-suppress-next-line PhanTypeMismatchArgument $this->getErrorFormatter()->getMessageFromException( $exception, $options ) @@ -1482,7 +1481,6 @@ abstract class ApiBase extends ContextSource { * @return never */ public function dieBlocked( Block $block ) { - // @phan-suppress-previous-line PhanTypeMissingReturn // Die using the appropriate message depending on block type if ( $block->getType() == Block::TYPE_AUTO ) { $this->dieWithError( @@ -1544,7 +1542,6 @@ abstract class ApiBase extends ContextSource { * @return never */ public function dieReadOnly() { - // @phan-suppress-previous-line PhanTypeMissingReturn $this->dieWithError( 'apierror-readonly', 'readonly', diff --git a/includes/api/ApiEditPage.php b/includes/api/ApiEditPage.php index 1b2c038c8da..8762d0cbf8e 100644 --- a/includes/api/ApiEditPage.php +++ b/includes/api/ApiEditPage.php @@ -621,6 +621,7 @@ class ApiEditPage extends ApiBase { // errors on the status. // @codeCoverageIgnoreStart case EditPage::AS_SPAM_ERROR: + // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset $status->fatal( 'apierror-spamdetected', $result['spam'] ); break; case EditPage::AS_READ_ONLY_PAGE_LOGGED: diff --git a/includes/api/ApiExpandTemplates.php b/includes/api/ApiExpandTemplates.php index 26fdea2a2b0..15af39b1ca0 100644 --- a/includes/api/ApiExpandTemplates.php +++ b/includes/api/ApiExpandTemplates.php @@ -119,6 +119,7 @@ class ApiExpandTemplates extends ApiBase { if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) { $this->parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS ); $dom = $this->parser->preprocessToDom( $params['text'] ); + // @phan-suppress-next-line PhanUndeclaredMethodInCallable if ( is_callable( [ $dom, 'saveXML' ] ) ) { // @phan-suppress-next-line PhanUndeclaredMethod $xml = $dom->saveXML(); diff --git a/includes/api/ApiQueryRevisionsBase.php b/includes/api/ApiQueryRevisionsBase.php index 3930811ed01..b03680270c6 100644 --- a/includes/api/ApiQueryRevisionsBase.php +++ b/includes/api/ApiQueryRevisionsBase.php @@ -580,6 +580,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase { 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(); diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php index 4c048eb3c11..a6971bc0198 100644 --- a/includes/api/ApiUpload.php +++ b/includes/api/ApiUpload.php @@ -414,7 +414,6 @@ class ApiUpload extends ApiBase { * @return never */ private function dieRecoverableError( $errors, $parameter = null ) { - // @phan-suppress-previous-line PhanTypeMissingReturn $this->performStash( 'optional', $data ); if ( $parameter ) { @@ -441,7 +440,6 @@ class ApiUpload extends ApiBase { * @return never */ public function dieStatusWithCode( $status, $overrideCode, $moreExtraData = null ) { - // @phan-suppress-previous-line PhanTypeMissingReturn $sv = StatusValue::newGood(); foreach ( $status->getErrors() as $error ) { $msg = ApiMessage::create( $error, $overrideCode ); @@ -654,7 +652,6 @@ class ApiUpload extends ApiBase { * @return never */ protected function checkVerification( array $verification ) { - // @phan-suppress-previous-line PhanTypeMissingReturn switch ( $verification['status'] ) { // Recoverable errors case UploadBase::MIN_LENGTH_PARTNAME: diff --git a/includes/auth/ButtonAuthenticationRequest.php b/includes/auth/ButtonAuthenticationRequest.php index f6c7b6a5084..d82cb962c8f 100644 --- a/includes/auth/ButtonAuthenticationRequest.php +++ b/includes/auth/ButtonAuthenticationRequest.php @@ -103,6 +103,7 @@ class ButtonAuthenticationRequest extends AuthenticationRequest { } elseif ( is_string( $data['label'] ) ) { $data['label'] = new Message( $data['label'] ); } elseif ( is_array( $data['label'] ) && $data['label'] ) { + // @phan-suppress-next-line PhanParamTooFewUnpack Should infer non-emptiness from above $data['label'] = Message::newFromKey( ...$data['label'] ); } if ( !isset( $data['help'] ) ) { @@ -110,6 +111,7 @@ class ButtonAuthenticationRequest extends AuthenticationRequest { } elseif ( is_string( $data['help'] ) ) { $data['help'] = new Message( $data['help'] ); } elseif ( is_array( $data['help'] ) && $data['help'] ) { + // @phan-suppress-next-line PhanParamTooFewUnpack Should infer non-emptiness from above $data['help'] = Message::newFromKey( ...$data['help'] ); } $ret = new static( $data['name'], $data['label'], $data['help'] ); diff --git a/includes/block/BlockManager.php b/includes/block/BlockManager.php index 2fec68afa02..6109a8ec938 100644 --- a/includes/block/BlockManager.php +++ b/includes/block/BlockManager.php @@ -195,7 +195,6 @@ class BlockManager { } elseif ( count( $blocks ) === 1 ) { return $blocks[ 0 ]; } else { - // @phan-suppress-next-line SecurityCheck-DoubleEscaped return new CompositeBlock( [ 'address' => $ip, 'reason' => new Message( 'blockedtext-composite-reason' ), @@ -253,14 +252,12 @@ class BlockManager { if ( !in_array( $ip, $this->options->get( MainConfigNames::ProxyWhitelist ) ) ) { // Local list if ( $this->isLocallyBlockedProxy( $ip ) ) { - // @phan-suppress-next-line SecurityCheck-DoubleEscaped $blocks[] = new SystemBlock( [ 'reason' => new Message( 'proxyblockreason' ), 'address' => $ip, 'systemBlock' => 'proxy', ] ); } elseif ( $isAnon && $this->isDnsBlacklisted( $ip ) ) { - // @phan-suppress-next-line SecurityCheck-DoubleEscaped $blocks[] = new SystemBlock( [ 'reason' => new Message( 'sorbsreason' ), 'address' => $ip, @@ -272,7 +269,6 @@ class BlockManager { // Soft blocking if ( $isAnon && IPUtils::isInRanges( $ip, $this->options->get( MainConfigNames::SoftBlockRanges ) ) ) { - // @phan-suppress-next-line SecurityCheck-DoubleEscaped $blocks[] = new SystemBlock( [ 'address' => $ip, 'reason' => new Message( 'softblockrangesreason', [ $ip ] ), diff --git a/includes/block/DatabaseBlock.php b/includes/block/DatabaseBlock.php index 698dd48d030..cc0e2362d85 100644 --- a/includes/block/DatabaseBlock.php +++ b/includes/block/DatabaseBlock.php @@ -266,7 +266,6 @@ class DatabaseBlock extends AbstractBlock { $conds['ipb_address'][] = (string)$target; $conds['ipb_address'] = array_unique( $conds['ipb_address'] ); $conds[] = self::getRangeCond( IPUtils::toHex( $target ) ); - // @phan-suppress-next-line SecurityCheck-SQLInjection $conds = $db->makeList( $conds, LIST_OR ); break; @@ -274,7 +273,6 @@ class DatabaseBlock extends AbstractBlock { list( $start, $end ) = IPUtils::parseRange( $target ); $conds['ipb_address'][] = (string)$target; $conds[] = self::getRangeCond( $start, $end ); - // @phan-suppress-next-line SecurityCheck-SQLInjection $conds = $db->makeList( $conds, LIST_OR ); break; @@ -284,7 +282,6 @@ class DatabaseBlock extends AbstractBlock { } $blockQuery = self::getQueryInfo(); - // @phan-suppress-next-line SecurityCheck-SQLInjection $res = $db->select( $blockQuery['tables'], $blockQuery['fields'], diff --git a/includes/diff/DifferenceEngineSlotDiffRenderer.php b/includes/diff/DifferenceEngineSlotDiffRenderer.php index 0cbededab37..e371fb7d5af 100644 --- a/includes/diff/DifferenceEngineSlotDiffRenderer.php +++ b/includes/diff/DifferenceEngineSlotDiffRenderer.php @@ -54,7 +54,6 @@ class DifferenceEngineSlotDiffRenderer extends SlotDiffRenderer { /** @inheritDoc */ public function getDiff( Content $oldContent = null, Content $newContent = null ) { $this->normalizeContents( $oldContent, $newContent ); - // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Null handled by normalizeContents return $this->differenceEngine->generateContentDiffBody( $oldContent, $newContent ); } diff --git a/includes/filerepo/file/File.php b/includes/filerepo/file/File.php index efae726d350..50ab75b8cd7 100644 --- a/includes/filerepo/file/File.php +++ b/includes/filerepo/file/File.php @@ -36,7 +36,6 @@ use MediaWiki\User\UserIdentity; * @ingroup FileAbstraction */ -// @phan-file-suppress PhanTypeMissingReturn false positives /** * Implements some public methods and some protected utility functions which * are required by multiple child classes. Contains stub functionality for diff --git a/includes/htmlform/fields/HTMLAutoCompleteSelectField.php b/includes/htmlform/fields/HTMLAutoCompleteSelectField.php index a2ac801cd0a..e861b28f82d 100644 --- a/includes/htmlform/fields/HTMLAutoCompleteSelectField.php +++ b/includes/htmlform/fields/HTMLAutoCompleteSelectField.php @@ -44,7 +44,6 @@ class HTMLAutoCompleteSelectField extends HTMLTextField { if ( array_key_exists( 'autocomplete-data-messages', $this->mParams ) ) { foreach ( $this->mParams['autocomplete-data-messages'] as $key => $value ) { - // @phan-suppress-next-line PhanTypeMismatchArgument False positive, $key is documented as string $key = $this->msg( $key )->plain(); $this->autocompleteData[$key] = strval( $value ); } diff --git a/includes/htmlform/fields/HTMLCheckMatrix.php b/includes/htmlform/fields/HTMLCheckMatrix.php index 71143d9c4ea..667c95330ba 100644 --- a/includes/htmlform/fields/HTMLCheckMatrix.php +++ b/includes/htmlform/fields/HTMLCheckMatrix.php @@ -99,7 +99,6 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable { // Build the column headers $headerContents = Html::rawElement( 'td', [], "\u{00A0}" ); foreach ( $columns as $columnLabel => $columnTag ) { - // @phan-suppress-next-line PhanTypeMismatchArgument False positive, labels are documented as string $headerContents .= Html::rawElement( 'th', [], $columnLabel ); } $thead = Html::rawElement( 'tr', [], "\n$headerContents\n" ); diff --git a/includes/htmlform/fields/HTMLFormFieldCloner.php b/includes/htmlform/fields/HTMLFormFieldCloner.php index 8ae114548e9..dbf0bc2bdba 100644 --- a/includes/htmlform/fields/HTMLFormFieldCloner.php +++ b/includes/htmlform/fields/HTMLFormFieldCloner.php @@ -485,7 +485,6 @@ class HTMLFormFieldCloner extends HTMLFormField { } $template = $this->getInputHTMLForKey( $this->uniqueId, [] ); - // @phan-suppress-next-line SecurityCheck-DoubleEscaped data-template contains html, but that is okay here $html = Html::rawElement( 'ul', [ 'id' => "mw-htmlform-cloner-list-{$this->mID}", 'class' => 'mw-htmlform-cloner-ul', @@ -558,7 +557,6 @@ class HTMLFormFieldCloner extends HTMLFormField { } $template = $this->getInputOOUIForKey( $this->uniqueId, [] ); - // @phan-suppress-next-line SecurityCheck-DoubleEscaped data-template contains html, but that is okay here $html = Html::rawElement( 'ul', [ 'id' => "mw-htmlform-cloner-list-{$this->mID}", 'class' => 'mw-htmlform-cloner-ul', diff --git a/includes/installer/DatabaseInstaller.php b/includes/installer/DatabaseInstaller.php index 4ca26af4037..a36c066f119 100644 --- a/includes/installer/DatabaseInstaller.php +++ b/includes/installer/DatabaseInstaller.php @@ -229,7 +229,6 @@ abstract class DatabaseInstaller { $this->db->setFlag( DBO_DDLMODE ); $this->db->begin( __METHOD__ ); - // @phan-suppress-next-line SecurityCheck-PathTraversal False positive $error = $this->db->sourceFile( call_user_func( [ $this, $sourceFileMethod ], $this->db ) ); diff --git a/includes/installer/Installer.php b/includes/installer/Installer.php index 4c0c66df3d8..50156d31cc4 100644 --- a/includes/installer/Installer.php +++ b/includes/installer/Installer.php @@ -1377,7 +1377,6 @@ abstract class Installer { $info += $jsonStatus->value; } - // @phan-suppress-next-line SecurityCheckMulti return Status::newGood( $info ); } diff --git a/includes/installer/PostgresInstaller.php b/includes/installer/PostgresInstaller.php index ce9873d71fd..16fa630a16f 100644 --- a/includes/installer/PostgresInstaller.php +++ b/includes/installer/PostgresInstaller.php @@ -196,7 +196,6 @@ class PostgresInstaller extends DatabaseInstaller { $conn = $status->value; $conn->clearFlag( DBO_TRX ); $conn->commit( __METHOD__ ); - // @phan-suppress-next-line SecurityCheck-DoubleEscaped $this->pgConns[$type] = $conn; } diff --git a/includes/installer/WebInstaller.php b/includes/installer/WebInstaller.php index be561a9cb4b..a8067623bfa 100644 --- a/includes/installer/WebInstaller.php +++ b/includes/installer/WebInstaller.php @@ -261,7 +261,6 @@ class WebInstaller extends Installer { # Execute the page. $this->currentPageName = $page->getName(); - // @phan-suppress-next-line PhanTypeMismatchArgumentNullable pageName is not null here $this->startPageWrapper( $pageName ); if ( $page->isSlow() ) { @@ -275,7 +274,6 @@ class WebInstaller extends Installer { if ( $result == 'skip' ) { # Page skipped without explicit submission. # Skip it when we click "back" so that we don't just go forward again. - // @phan-suppress-next-line PhanTypeMismatchDimAssignment pageName is not null here $this->skippedPages[$pageName] = true; $result = 'continue'; } else { diff --git a/includes/installer/WebInstallerOptions.php b/includes/installer/WebInstallerOptions.php index 091a747e1f7..64b82516020 100644 --- a/includes/installer/WebInstallerOptions.php +++ b/includes/installer/WebInstallerOptions.php @@ -205,7 +205,6 @@ class WebInstallerOptions extends WebInstallerPage { } $skinHtml .= '