From 89cdd0904488d00e78fb4434cf2cb7d60a071153 Mon Sep 17 00:00:00 2001 From: smiley Date: Sun, 21 Jul 2024 05:25:26 +0200 Subject: [PATCH] :octocat: switch phan for phpstan (see #277) --- .gitattributes | 39 ++--- .github/workflows/ci.yml | 4 +- .gitignore | 1 + .phan/config.php | 60 -------- .phan/stubs/misc.php | 9 -- composer.json | 8 +- examples/imagickImageAsBackground.php | 2 + examples/imagickWithLogo.php | 2 + examples/qrcode-interactive.php | 20 ++- examples/svgMeltedModules.php | 4 + examples/svgRandomColoredDots.php | 8 +- examples/svgRoundQuietzone.php | 7 + examples/svgWithLogo.php | 4 + examples/svgWithLogoAndCustomShapes.php | 4 + phpstan-baseline.neon | 141 ++++++++++++++++++ phpstan.dist.neon | 24 +++ src/Common/BitBuffer.php | 8 +- src/Common/GenericGFPoly.php | 3 +- src/Common/LuminanceSourceAbstract.php | 1 + src/Common/LuminanceSourceInterface.php | 4 +- src/Common/MaskPattern.php | 14 +- src/Common/Mode.php | 2 +- src/Data/AlphaNum.php | 41 ++--- src/Data/Number.php | 35 ++--- src/Data/QRData.php | 4 +- src/Data/QRMatrix.php | 9 +- src/Data/ReedSolomonEncoder.php | 8 +- src/Decoder/Binarizer.php | 4 + src/Decoder/BitMatrix.php | 2 +- src/Decoder/DecoderResult.php | 2 + src/Decoder/ReedSolomonDecoder.php | 15 +- src/Detector/AlignmentPatternFinder.php | 1 + src/Detector/FinderPatternFinder.php | 2 - src/Detector/GridSampler.php | 1 + src/Detector/PerspectiveTransform.php | 5 +- src/Output/CssColorModuleValueTrait.php | 14 +- src/Output/QREps.php | 2 + src/Output/QRFpdf.php | 4 +- src/Output/QRGdImage.php | 2 +- src/Output/QRMarkupXML.php | 24 +-- src/Output/QROutputAbstract.php | 21 ++- src/Output/QRStringJSON.php | 9 ++ src/Output/QRStringText.php | 4 + src/Output/RGBArrayModuleValueTrait.php | 17 ++- src/QRCode.php | 10 +- src/QRCodeReaderOptionsTrait.php | 5 + src/QROptionsTrait.php | 57 +++++++ tests/Common/BitBufferTest.php | 3 + tests/Common/ECICharsetTest.php | 8 +- tests/Common/EccLevelTest.php | 2 +- tests/Common/MaskPatternTest.php | 2 +- tests/Common/ModeTest.php | 6 +- tests/Common/VersionTest.php | 2 +- tests/Data/AlphaNumTest.php | 2 + tests/Data/ByteTest.php | 2 + tests/Data/DataInterfaceTestAbstract.php | 9 +- tests/Data/ECITest.php | 16 +- tests/Data/HanziTest.php | 2 + tests/Data/KanjiTest.php | 2 + tests/Data/NumberTest.php | 2 + .../CssColorModuleValueProviderTrait.php | 3 - tests/Output/QREpsTest.php | 1 + tests/Output/QRFpdfTest.php | 1 + tests/Output/QRGdImageAVIFTest.php | 3 +- tests/Output/QRGdImageTestAbstract.php | 1 + tests/Output/QRImagickTest.php | 1 + tests/Output/QRInterventionImageTest.php | 1 + tests/Output/QROutputTestAbstract.php | 3 + tests/Output/QRStringTextTest.php | 3 + tests/QRCodeReaderImagickTest.php | 3 + tests/QRCodeReaderTestAbstract.php | 5 +- tests/QROptionsTest.php | 6 +- 72 files changed, 539 insertions(+), 217 deletions(-) delete mode 100644 .phan/config.php delete mode 100644 .phan/stubs/misc.php create mode 100644 phpstan-baseline.neon create mode 100644 phpstan.dist.neon diff --git a/.gitattributes b/.gitattributes index 5f1e42f08..d108e602d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,20 +1,23 @@ -/.build export-ignore -/.github export-ignore -/.idea export-ignore -/.phan export-ignore -/.phpdoc export-ignore -/benchmark export-ignore -/docs export-ignore -/examples export-ignore -/tests export-ignore -/.editorconfig export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.readthedocs.yml export-ignore -/phpbench.json export-ignore -/phpcs.xml.dist export-ignore -/phpdoc.xml.dist export-ignore -/phpmd.xml.dist export-ignore -/phpunit.xml.dist export-ignore +/.build export-ignore +/.github export-ignore +/.idea export-ignore +/.phan export-ignore +/.phpdoc export-ignore +/benchmark export-ignore +/docs export-ignore +/examples export-ignore +/tests export-ignore +/.editorconfig export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.readthedocs.yml export-ignore +/composer.lock export-ignore +/phpbench.json export-ignore +/phpcs.xml.dist export-ignore +/phpdoc.xml.dist export-ignore +/phpmd.xml.dist export-ignore +/phpunit.xml.dist export-ignore +/phpstan.dist.neon export-ignore +/phpstan-baseline.neon export-ignore *.php diff=php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67ba4e0bd..470d9bdb0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} - extensions: ast, ${{ env.PHP_EXTENSIONS }} + extensions: ${{ env.PHP_EXTENSIONS }} ini-values: ${{ env.PHP_INI_VALUES }} coverage: none @@ -49,6 +49,8 @@ jobs: - name: "Run phan" run: php vendor/bin/phan --target-php-version=${{ matrix.php-version }} + - name: "Run PHPStan" + run: php vendor/bin/phpstan tests: diff --git a/.gitignore b/.gitignore index 9cfb4de0f..23952c457 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ phpcs.xml phpdoc.xml phpmd.xml phpunit.xml +phpstan.neon tests/Performance/*.json diff --git a/.phan/config.php b/.phan/config.php deleted file mode 100644 index 82154d3ff..000000000 --- a/.phan/config.php +++ /dev/null @@ -1,60 +0,0 @@ - null, - 'minimum_target_php_version' => '8.2', - - // A list of directories that should be parsed for class and - // method information. After excluding the directories - // defined in exclude_analysis_directory_list, the remaining - // files will be statically analyzed for errors. - // - // Thus, both first-party and third-party code being used by - // your application should be included in this list. - 'directory_list' => [ - 'benchmark', - 'examples', - 'src', - 'tests', - 'vendor', - '.phan/stubs', - ], - - // A regex used to match every file name that you want to - // exclude from parsing. Actual value will exclude every - // "test", "tests", "Test" and "Tests" folders found in - // "vendor/" directory. - 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', - - // A directory list that defines files that will be excluded - // from static analysis, but whose class and method - // information should be included. - // - // Generally, you'll want to include the directories for - // third-party code (such as "vendor/") in this list. - // - // n.b.: If you'd like to parse but not analyze 3rd - // party code, directories containing that code - // should be added to both the `directory_list` - // and `exclude_analysis_directory_list` arrays. - 'exclude_analysis_directory_list' => [ - 'vendor/', - '.phan/stubs', - ], - 'suppress_issue_types' => [ - 'PhanAccessMethodInternal', - ], -]; diff --git a/.phan/stubs/misc.php b/.phan/stubs/misc.php deleted file mode 100644 index 163eb886e..000000000 --- a/.phan/stubs/misc.php +++ /dev/null @@ -1,9 +0,0 @@ - - * @copyright 2021 smiley - * @license MIT - */ diff --git a/composer.json b/composer.json index 7dd0447df..9a8ca86a6 100644 --- a/composer.json +++ b/composer.json @@ -55,9 +55,10 @@ "chillerlan/php-authenticator": "^5.2.1", "intervention/image": "^3.7", "phpbench/phpbench": "^1.2.15", - "phan/phan": "^5.4", "phpunit/phpunit": "^11.2", "phpmd/phpmd": "^2.15", + "phpstan/phpstan": "^1.11", + "phpstan/phpstan-deprecation-rules": "^1.2", "setasign/fpdf": "^1.8.2", "squizlabs/php_codesniffer": "^3.10" }, @@ -79,13 +80,14 @@ } }, "scripts": { - "phan": "@php vendor/bin/phan", "phpcs": "@php vendor/bin/phpcs", "phpbench":[ "Composer\\Config::disableProcessTimeout", "@php vendor/bin/phpbench run" ], - "phpunit": "@php vendor/bin/phpunit" + "phpunit": "@php vendor/bin/phpunit", + "phpstan": "@php vendor/bin/phpstan", + "phpstan-baseline": "@php vendor/bin/phpstan --generate-baseline" }, "config": { "lock": false, diff --git a/examples/imagickImageAsBackground.php b/examples/imagickImageAsBackground.php index 1807e1c2d..1e5d039dc 100644 --- a/examples/imagickImageAsBackground.php +++ b/examples/imagickImageAsBackground.php @@ -56,6 +56,8 @@ class QRImagickImageAsBackground extends QRImagick{ /** * augment the QROptions class + * + * @property string $background */ class ImageAsBackgroundOptions extends QROptions{ diff --git a/examples/imagickWithLogo.php b/examples/imagickWithLogo.php index 21141a848..b89b1fc02 100644 --- a/examples/imagickWithLogo.php +++ b/examples/imagickWithLogo.php @@ -65,6 +65,8 @@ class QRImagickWithLogo extends QRImagick{ /** * augment the QROptions class + * + * @property string $pngLogo */ class ImagickWithLogoOptions extends QROptions{ diff --git a/examples/qrcode-interactive.php b/examples/qrcode-interactive.php index f0227a002..e602b72dd 100644 --- a/examples/qrcode-interactive.php +++ b/examples/qrcode-interactive.php @@ -13,6 +13,15 @@ use chillerlan\QRCode\Data\QRMatrix; require_once '../vendor/autoload.php'; +/** + * @param array $response + */ +function sendResponse(array $response):never{ + header('Content-type: application/json;charset=utf-8;'); + echo json_encode($response); + exit; +} + try{ $moduleValues = [ @@ -89,14 +98,3 @@ catch(Throwable $e){ header('HTTP/1.1 500 Internal Server Error'); sendResponse(['error' => $e->getMessage()]); } - -exit; - -/** - * @param array $response - */ -function sendResponse(array $response){ - header('Content-type: application/json;charset=utf-8;'); - echo json_encode($response); - exit; -} diff --git a/examples/svgMeltedModules.php b/examples/svgMeltedModules.php index f9bdaa408..b338e8000 100644 --- a/examples/svgMeltedModules.php +++ b/examples/svgMeltedModules.php @@ -217,6 +217,10 @@ class MeltedSVGQRCodeOutput extends QRMarkupSVG{ /** * the augmented options class + * + * @property bool $melt + * @property bool $inverseMelt + * @property float $meltRadius */ class MeltedOutputOptions extends QROptions{ diff --git a/examples/svgRandomColoredDots.php b/examples/svgRandomColoredDots.php index 0883b7782..e6bb62068 100644 --- a/examples/svgRandomColoredDots.php +++ b/examples/svgRandomColoredDots.php @@ -81,13 +81,19 @@ class RandomDotsSVGOutput extends QRMarkupSVG{ } -// the extended options with the $dotColors option + +/** + * the extended options with the $dotColors option + * + * @property array $dotColors + */ class RandomDotsOptions extends QROptions{ /** * a map of $M_TYPE_LAYER => color * * @see \array_rand() + * @var array */ protected array $dotColors = []; diff --git a/examples/svgRoundQuietzone.php b/examples/svgRoundQuietzone.php index 6886128d1..e8959b202 100644 --- a/examples/svgRoundQuietzone.php +++ b/examples/svgRoundQuietzone.php @@ -210,6 +210,12 @@ class RoundQuietzoneSVGoutput extends QRMarkupSVG{ /** * the augmented options class + * + * @property int $additionalModules + * @property array $dotColors + * @property string $svgLogo + * @property float $svgLogoScale + * @property string $svgLogoCssClass */ class RoundQuietzoneOptions extends QROptions{ @@ -231,6 +237,7 @@ class RoundQuietzoneOptions extends QROptions{ * a map of $M_TYPE_LAYER => color * * @see \array_rand() + * @var array */ protected array $dotColors = []; diff --git a/examples/svgWithLogo.php b/examples/svgWithLogo.php index 1a8eb96d6..d61cde436 100644 --- a/examples/svgWithLogo.php +++ b/examples/svgWithLogo.php @@ -72,6 +72,10 @@ class QRSvgWithLogo extends QRMarkupSVG{ /** * augment the QROptions class + * + * @property string $svgLogo + * @property float $svgLogoScale + * @property string $svgLogoCssClass */ class SVGWithLogoOptions extends QROptions{ // path to svg logo diff --git a/examples/svgWithLogoAndCustomShapes.php b/examples/svgWithLogoAndCustomShapes.php index 3b079bf8b..924fe2a22 100644 --- a/examples/svgWithLogoAndCustomShapes.php +++ b/examples/svgWithLogoAndCustomShapes.php @@ -130,6 +130,10 @@ class QRSvgWithLogoAndCustomShapes extends QRMarkupSVG{ /** * augment the QROptions class + * + * @property string $svgLogo + * @property float $svgLogoScale + * @property string $svgLogoCssClass */ class SVGWithLogoAndCustomShapesOptions extends QROptions{ // path to svg logo diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 000000000..7c8940ef5 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,141 @@ +parameters: + ignoreErrors: + - + message: "#^Property chillerlan\\\\QRCode\\\\QROptions\\:\\:\\$eccLevel \\(int\\) does not accept string\\.$#" + count: 1 + path: examples/custom_output.php + + - + message: "#^Parameter \\#2 \\$color of function imagecolortransparent expects int\\|null, int\\<0, max\\>\\|false given\\.$#" + count: 1 + path: examples/imageWithText.php + + - + message: "#^Parameter \\#6 \\$color of function imagechar expects int, int\\<0, max\\>\\|false given\\.$#" + count: 1 + path: examples/imageWithText.php + + - + message: "#^Parameter \\#6 \\$color of function imagefilledrectangle expects int, int\\<0, max\\>\\|false given\\.$#" + count: 1 + path: examples/imageWithText.php + + - + message: "#^Parameter \\#1 \\(Intervention\\\\Image\\\\Interfaces\\\\ImageInterface\\|string\\) of echo cannot be converted to string\\.$#" + count: 1 + path: examples/intervention-image.php + + - + message: "#^Method RandomDotsSVGOutput\\:\\:collectModules\\(\\) should return array\\ but returns array\\\\>\\.$#" + count: 1 + path: examples/svgRandomColoredDots.php + + - + message: "#^Method RoundQuietzoneSVGoutput\\:\\:collectModules\\(\\) should return array\\ but returns array\\\\>\\.$#" + count: 1 + path: examples/svgRoundQuietzone.php + + - + message: "#^Parameter \\#1 \\$data of function imagecreatefromstring expects string, string\\|false given\\.$#" + count: 1 + path: src/Common/GDLuminanceSource.php + + - + message: "#^Parameter \\#1 \\$gdImage of class chillerlan\\\\QRCode\\\\Common\\\\GDLuminanceSource constructor expects GdImage, GdImage\\|false given\\.$#" + count: 2 + path: src/Common/GDLuminanceSource.php + + - + message: "#^Parameter \\#2 \\$color of function imagecolorsforindex expects int, int\\<0, max\\>\\|false given\\.$#" + count: 1 + path: src/Common/GDLuminanceSource.php + + - + message: "#^Parameter \\#1 \\$maskPattern of class chillerlan\\\\QRCode\\\\Common\\\\MaskPattern constructor expects int, int\\|false given\\.$#" + count: 1 + path: src/Common/MaskPattern.php + + - + message: "#^Method chillerlan\\\\QRCode\\\\Common\\\\Version\\:\\:getRSBlocks\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/Common/Version.php + + - + message: "#^Parameter \\#1 \\$encoding of function mb_detect_order expects non\\-empty\\-list\\\\|non\\-falsy\\-string\\|null, array\\{string, 'UTF\\-8', 'GB2312', 'GB18030', 'CP936', 'EUC\\-CN', 'HZ'\\} given\\.$#" + count: 1 + path: src/Data/Hanzi.php + + - + message: "#^Parameter \\#1 \\$encoding of function mb_detect_order expects non\\-empty\\-list\\\\|non\\-falsy\\-string\\|null, array\\{string, 'UTF\\-8', 'SJIS', 'SJIS\\-2004'\\} given\\.$#" + count: 1 + path: src/Data/Kanji.php + + - + message: "#^Parameter \\#1 \\$version of class chillerlan\\\\QRCode\\\\Data\\\\ReedSolomonEncoder constructor expects chillerlan\\\\QRCode\\\\Common\\\\Version, chillerlan\\\\QRCode\\\\Common\\\\Version\\|null given\\.$#" + count: 1 + path: src/Data/QRMatrix.php + + - + message: "#^Parameter \\#2 \\$eccLevel of class chillerlan\\\\QRCode\\\\Data\\\\ReedSolomonEncoder constructor expects chillerlan\\\\QRCode\\\\Common\\\\EccLevel, chillerlan\\\\QRCode\\\\Common\\\\EccLevel\\|null given\\.$#" + count: 1 + path: src/Data/QRMatrix.php + + - + message: "#^Parameter \\#1 \\$maskPattern of method chillerlan\\\\QRCode\\\\Data\\\\QRMatrix\\:\\:mask\\(\\) expects chillerlan\\\\QRCode\\\\Common\\\\MaskPattern, chillerlan\\\\QRCode\\\\Common\\\\MaskPattern\\|null given\\.$#" + count: 1 + path: src/Decoder/BitMatrix.php + + - + message: "#^Parameter \\#1 \\$version of class chillerlan\\\\QRCode\\\\Data\\\\QRMatrix constructor expects chillerlan\\\\QRCode\\\\Common\\\\Version, chillerlan\\\\QRCode\\\\Common\\\\Version\\|null given\\.$#" + count: 1 + path: src/Decoder/BitMatrix.php + + - + message: "#^Parameter \\#2 \\$b of method chillerlan\\\\QRCode\\\\Decoder\\\\BitMatrix\\:\\:numBitsDiffering\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: src/Decoder/BitMatrix.php + + - + message: "#^Parameter \\#2 \\$eccLevel of class chillerlan\\\\QRCode\\\\Data\\\\QRMatrix constructor expects chillerlan\\\\QRCode\\\\Common\\\\EccLevel, chillerlan\\\\QRCode\\\\Common\\\\EccLevel\\|null given\\.$#" + count: 1 + path: src/Decoder/BitMatrix.php + + - + message: "#^Property chillerlan\\\\QRCode\\\\Decoder\\\\Decoder\\:\\:\\$options is never read, only written\\.$#" + count: 1 + path: src/Decoder/Decoder.php + + - + message: "#^Method chillerlan\\\\QRCode\\\\Decoder\\\\ReedSolomonDecoder\\:\\:deinterleaveRawBytes\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/Decoder/ReedSolomonDecoder.php + + - + message: "#^Method chillerlan\\\\QRCodeTest\\\\Common\\\\MaskPatternTest\\:\\:assertMask\\(\\) has parameter \\$expected with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/Common/MaskPatternTest.php + + - + message: "#^Method chillerlan\\\\QRCodeTest\\\\Common\\\\MaskPatternTest\\:\\:maskPatternProvider\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/Common/MaskPatternTest.php + + - + message: "#^Method chillerlan\\\\QRCodeTest\\\\Common\\\\MaskPatternTest\\:\\:testMask\\(\\) has parameter \\$expected with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/Common/MaskPatternTest.php + + - + message: "#^Parameter \\#1 \\$string of static method chillerlan\\\\QRCode\\\\Data\\\\QRDataModeInterface\\:\\:validateString\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/Data/DataInterfaceTestAbstract.php + + - + message: "#^Parameter \\#2 \\$to_encoding of function mb_convert_encoding expects string, string\\|null given\\.$#" + count: 1 + path: tests/Data/ECITest.php + + - + message: "#^Parameter \\#1 \\$blob of method chillerlan\\\\QRCode\\\\QRCode\\:\\:readFromBlob\\(\\) expects string, GdImage\\|string given\\.$#" + count: 1 + path: tests/Data/QRDataTest.php diff --git a/phpstan.dist.neon b/phpstan.dist.neon new file mode 100644 index 000000000..ce6281b4c --- /dev/null +++ b/phpstan.dist.neon @@ -0,0 +1,24 @@ +# https://phpstan.org/config-reference + +parameters: + level: 8 + tmpDir: .build/phpstan-cache + paths: + - examples + - src + - tests + + treatPhpDocTypesAsCertain: false + + ignoreErrors: + # the only place where these instances *may* be null is in the Decoder\BitMatrix class + - message: "#^Cannot call method [\\w]+\\(\\) on chillerlan\\\\QRCode\\\\Common\\\\EccLevel\\|null\\.$#" + - message: "#^Cannot call method [\\w]+\\(\\) on chillerlan\\\\QRCode\\\\Common\\\\MaskPattern\\|null\\.$#" + - message: "#^Cannot call method [\\w]+\\(\\) on chillerlan\\\\QRCode\\\\Common\\\\Version\\|null\\.$#" + + +includes: + - phpstan-baseline.neon + - vendor/phpstan/phpstan/conf/bleedingEdge.neon + - vendor/phpstan/phpstan-deprecation-rules/rules.neon + - vendor/chillerlan/php-settings-container/rules-magic-access.neon diff --git a/src/Common/BitBuffer.php b/src/Common/BitBuffer.php index 91c04052e..d6be3fe9c 100644 --- a/src/Common/BitBuffer.php +++ b/src/Common/BitBuffer.php @@ -42,6 +42,8 @@ final class BitBuffer{ /** * BitBuffer constructor. + * + * @param int[] $bytes */ public function __construct(array $bytes = []){ $this->buffer = $bytes; @@ -89,14 +91,16 @@ final class BitBuffer{ /** * returns the buffer content * - * to debug: array_map(fn($v) => sprintf('%08b', $v), $bitBuffer->getBuffer()) + * to debug: `array_map(fn($v) => sprintf('%08b', $v), $bitBuffer->getBuffer())` + * + * @return int[] */ public function getBuffer():array{ return $this->buffer; } /** - * @return int number of bits that can be read successfully + * Returns the number of bits that can be read successfully */ public function available():int{ return ((8 * ($this->length - $this->bytesRead)) - $this->bitsRead); diff --git a/src/Common/GenericGFPoly.php b/src/Common/GenericGFPoly.php index 7aeafc96a..161bc7635 100644 --- a/src/Common/GenericGFPoly.php +++ b/src/Common/GenericGFPoly.php @@ -25,10 +25,11 @@ use function array_fill, array_slice, array_splice, count; */ final class GenericGFPoly{ + /** @var int[] */ private array $coefficients; /** - * @param array $coefficients array coefficients as ints representing elements of GF(size), arranged + * @param int[] $coefficients array coefficients as ints representing elements of GF(size), arranged * from most significant (highest-power term) coefficient to the least significant * @param int|null $degree * diff --git a/src/Common/LuminanceSourceAbstract.php b/src/Common/LuminanceSourceAbstract.php index de04801f8..a69e410e7 100644 --- a/src/Common/LuminanceSourceAbstract.php +++ b/src/Common/LuminanceSourceAbstract.php @@ -26,6 +26,7 @@ use function array_slice, array_splice, file_exists, is_file, is_readable, realp abstract class LuminanceSourceAbstract implements LuminanceSourceInterface{ protected SettingsContainerInterface|QROptions $options; + /** @var int[] */ protected array $luminances; protected int $width; protected int $height; diff --git a/src/Common/LuminanceSourceInterface.php b/src/Common/LuminanceSourceInterface.php index bb691148a..59efc8393 100644 --- a/src/Common/LuminanceSourceInterface.php +++ b/src/Common/LuminanceSourceInterface.php @@ -21,7 +21,7 @@ interface LuminanceSourceInterface{ * Fetches luminance data for the underlying bitmap. Values should be fetched using: * `int luminance = array[y * width + x] & 0xff` * - * @return array A row-major 2D array of luminance values. Do not use result $length as it may be + * @return int[] A row-major 2D array of luminance values. Do not use result $length as it may be * larger than $width * $height bytes on some platforms. Do not modify the contents * of the result. */ @@ -46,7 +46,7 @@ interface LuminanceSourceInterface{ * * @param int $y The row to fetch, which must be in [0,getHeight()) * - * @return array An array containing the luminance data. + * @return int[] An array containing the luminance data. * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ public function getRow(int $y):array; diff --git a/src/Common/MaskPattern.php b/src/Common/MaskPattern.php index 5c3ea93c1..5455310b3 100644 --- a/src/Common/MaskPattern.php +++ b/src/Common/MaskPattern.php @@ -139,6 +139,8 @@ final class MaskPattern{ /** * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and * give penalty to them. Example: 00000 or 11111. + * + * @param bool[][] $matrix */ public static function testRule1(array $matrix, int $height, int $width):int{ $penalty = 0; @@ -157,7 +159,7 @@ final class MaskPattern{ } /** - * + * @param bool[] $rc */ private static function applyRule1(array $rc):int{ $penalty = 0; @@ -191,6 +193,8 @@ final class MaskPattern{ * Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give * penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a * penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. + * + * @param bool[][] $matrix */ public static function testRule2(array $matrix, int $height, int $width):int{ $penalty = 0; @@ -224,6 +228,8 @@ final class MaskPattern{ * Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4 * starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we * find patterns like 000010111010000, we give penalty once. + * + * @param bool[][] $matrix */ public static function testRule3(array $matrix, int $height, int $width):int{ $penalties = 0; @@ -272,7 +278,7 @@ final class MaskPattern{ } /** - * + * @param bool[] $row */ private static function isWhiteHorizontal(array $row, int $width, int $from, int $to):bool{ @@ -290,7 +296,7 @@ final class MaskPattern{ } /** - * + * @param bool[][] $matrix */ private static function isWhiteVertical(array $matrix, int $height, int $x, int $from, int $to):bool{ @@ -310,6 +316,8 @@ final class MaskPattern{ /** * Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give * penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. + * + * @param bool[][] $matrix */ public static function testRule4(array $matrix, int $height, int $width):int{ $darkCells = 0; diff --git a/src/Common/Mode.php b/src/Common/Mode.php index 523d37919..461cea307 100644 --- a/src/Common/Mode.php +++ b/src/Common/Mode.php @@ -58,7 +58,7 @@ final class Mode{ /** * Map of data mode => interface (detection order) * - * @var string[] + * @var array */ public const INTERFACES = [ self::NUMBER => Number::class, diff --git a/src/Data/AlphaNum.php b/src/Data/AlphaNum.php index be9df2d25..23a90ad23 100644 --- a/src/Data/AlphaNum.php +++ b/src/Data/AlphaNum.php @@ -11,7 +11,7 @@ namespace chillerlan\QRCode\Data; use chillerlan\QRCode\Common\{BitBuffer, Mode}; -use function array_flip, ceil, intdiv, str_split; +use function ceil, intdiv, str_split; /** * Alphanumeric mode: 0 to 9, A to Z, space, $ % * + - . / : @@ -35,6 +35,18 @@ final class AlphaNum extends QRDataModeAbstract{ '+' => 40, '-' => 41, '.' => 42, '/' => 43, ':' => 44, ]; + /** + * @var string[] + */ + private const ORD_TO_CHAR = [ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', + '+', '-', '.', '/', ':', + ]; + /** * @inheritDoc */ @@ -78,7 +90,10 @@ final class AlphaNum extends QRDataModeAbstract{ // encode 2 characters in 11 bits for($i = 0; ($i + 1) < $len; $i += 2){ - $bitBuffer->put((self::CHAR_TO_ORD[$this->data[$i]] * 45 + self::CHAR_TO_ORD[$this->data[($i + 1)]]), 11); + $bitBuffer->put( + (self::CHAR_TO_ORD[$this->data[$i]] * 45 + self::CHAR_TO_ORD[$this->data[($i + 1)]]), + 11, + ); } // encode a remaining character in 6 bits @@ -95,19 +110,7 @@ final class AlphaNum extends QRDataModeAbstract{ * @throws \chillerlan\QRCode\Data\QRCodeDataException */ public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{ - $length = $bitBuffer->read(self::getLengthBits($versionNumber)); - $charmap = array_flip(self::CHAR_TO_ORD); - - // @todo - $toAlphaNumericChar = function(int $ord) use ($charmap):string{ - - if(isset($charmap[$ord])){ - return $charmap[$ord]; - } - - throw new QRCodeDataException('invalid character value: '.$ord); - }; - + $length = $bitBuffer->read(self::getLengthBits($versionNumber)); $result = ''; // Read two characters at a time while($length > 1){ @@ -116,9 +119,9 @@ final class AlphaNum extends QRDataModeAbstract{ throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore } - $nextTwoCharsBits = $bitBuffer->read(11); - $result .= $toAlphaNumericChar(intdiv($nextTwoCharsBits, 45)); - $result .= $toAlphaNumericChar($nextTwoCharsBits % 45); + $nextTwoCharsBits = $bitBuffer->read(11); + $result .= self::ORD_TO_CHAR[intdiv($nextTwoCharsBits, 45)]; + $result .= self::ORD_TO_CHAR[($nextTwoCharsBits % 45)]; $length -= 2; } @@ -128,7 +131,7 @@ final class AlphaNum extends QRDataModeAbstract{ throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore } - $result .= $toAlphaNumericChar($bitBuffer->read(6)); + $result .= self::ORD_TO_CHAR[$bitBuffer->read(6)]; } return $result; diff --git a/src/Data/Number.php b/src/Data/Number.php index 71f2b1fbd..83b61574d 100644 --- a/src/Data/Number.php +++ b/src/Data/Number.php @@ -11,7 +11,7 @@ namespace chillerlan\QRCode\Data; use chillerlan\QRCode\Common\{BitBuffer, Mode}; -use function array_flip, ceil, intdiv, str_split, substr, unpack; +use function ceil, intdiv, str_split, substr, unpack; /** * Numeric mode: decimal digits 0 to 9 @@ -28,6 +28,13 @@ final class Number extends QRDataModeAbstract{ '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, ]; + /** + * @var string[] + */ + private const ORD_TO_NUMBER = [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ]; + /** * @inheritDoc */ @@ -112,19 +119,7 @@ final class Number extends QRDataModeAbstract{ * @throws \chillerlan\QRCode\Data\QRCodeDataException */ public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{ - $length = $bitBuffer->read(self::getLengthBits($versionNumber)); - $charmap = array_flip(self::NUMBER_TO_ORD); - - // @todo - $toNumericChar = function(int $ord) use ($charmap):string{ - - if(isset($charmap[$ord])){ - return $charmap[$ord]; - } - - throw new QRCodeDataException('invalid character value: '.$ord); - }; - + $length = $bitBuffer->read(self::getLengthBits($versionNumber)); $result = ''; // Read three digits at a time while($length >= 3){ @@ -139,9 +134,9 @@ final class Number extends QRDataModeAbstract{ throw new QRCodeDataException('error decoding numeric value'); } - $result .= $toNumericChar(intdiv($threeDigitsBits, 100)); - $result .= $toNumericChar(intdiv($threeDigitsBits, 10) % 10); - $result .= $toNumericChar($threeDigitsBits % 10); + $result .= self::ORD_TO_NUMBER[intdiv($threeDigitsBits, 100)]; + $result .= self::ORD_TO_NUMBER[(intdiv($threeDigitsBits, 10) % 10)]; + $result .= self::ORD_TO_NUMBER[($threeDigitsBits % 10)]; $length -= 3; } @@ -158,8 +153,8 @@ final class Number extends QRDataModeAbstract{ throw new QRCodeDataException('error decoding numeric value'); } - $result .= $toNumericChar(intdiv($twoDigitsBits, 10)); - $result .= $toNumericChar($twoDigitsBits % 10); + $result .= self::ORD_TO_NUMBER[intdiv($twoDigitsBits, 10)]; + $result .= self::ORD_TO_NUMBER[($twoDigitsBits % 10)]; } elseif($length === 1){ // One digit left over to read @@ -173,7 +168,7 @@ final class Number extends QRDataModeAbstract{ throw new QRCodeDataException('error decoding numeric value'); } - $result .= $toNumericChar($digitBits); + $result .= self::ORD_TO_NUMBER[$digitBits]; } return $result; diff --git a/src/Data/QRData.php b/src/Data/QRData.php index 10230b77e..e3120b58c 100644 --- a/src/Data/QRData.php +++ b/src/Data/QRData.php @@ -54,6 +54,8 @@ final class QRData{ /** * QRData constructor. + * + * @param \chillerlan\QRCode\Data\QRDataModeInterface[] $dataSegments */ public function __construct(SettingsContainerInterface|QROptions $options, array $dataSegments = []){ $this->options = $options; @@ -146,7 +148,7 @@ final class QRData{ } $provisionalVersion = null; - + /** @var int $version */ foreach($this->maxBitsForEcc as $version => $maxBits){ if($length <= $maxBits){ diff --git a/src/Data/QRMatrix.php b/src/Data/QRMatrix.php index 9bf3d0b61..1499e7992 100755 --- a/src/Data/QRMatrix.php +++ b/src/Data/QRMatrix.php @@ -94,7 +94,7 @@ class QRMatrix{ * * @see \chillerlan\QRCode\Data\QRMatrix::checkNeighbours() * - * @var array + * @var int[][] */ protected const neighbours = [ 0b00000001 => [-1, -1], @@ -150,6 +150,8 @@ class QRMatrix{ /** * Creates a 2-dimensional array (square) of the given $size + * + * @return int[][] */ protected function createMatrix(int $size, int $value):array{ return array_fill(0, $size, array_fill(0, $size, $value)); @@ -173,7 +175,7 @@ class QRMatrix{ /** * Returns the data matrix, returns a pure boolean representation if $boolean is set to true * - * @return int[][]|bool[][] + * @return int[][] */ public function getMatrix(bool|null $boolean = null):array{ @@ -299,6 +301,8 @@ class QRMatrix{ /** * Checks whether the module at ($x, $y) is in the given array of $M_TYPES, * returns true if a match is found, otherwise false. + * + * @param int[] $M_TYPES */ public function checkTypeIn(int $x, int $y, array $M_TYPES):bool{ @@ -583,7 +587,6 @@ class QRMatrix{ * Rotates the matrix by 90 degrees clock wise */ public function rotate90():static{ - /** @phan-suppress-next-line PhanParamTooFewInternalUnpack */ $this->matrix = array_map((fn(int ...$a):array => array_reverse($a)), ...$this->matrix); return $this; diff --git a/src/Data/ReedSolomonEncoder.php b/src/Data/ReedSolomonEncoder.php index 60444378c..f5c42c0a7 100644 --- a/src/Data/ReedSolomonEncoder.php +++ b/src/Data/ReedSolomonEncoder.php @@ -22,7 +22,7 @@ final class ReedSolomonEncoder{ private Version $version; private EccLevel $eccLevel; - + /** @var int[] */ private array $interleavedData; private int $interleavedDataIndex; @@ -37,6 +37,7 @@ final class ReedSolomonEncoder{ /** * ECC encoding and interleaving * + * @return int[] * @throws \chillerlan\QRCode\QRCodeException */ public function interleaveEcBytes(BitBuffer $bitBuffer):array{ @@ -80,7 +81,8 @@ final class ReedSolomonEncoder{ } /** - * + * @param int[] $dataBytes + * @return int[] */ private function encode(array $dataBytes, int $ecByteCount):array{ $rsPoly = new GenericGFPoly([1]); @@ -112,7 +114,7 @@ final class ReedSolomonEncoder{ } /** - * + * @param int[][] $byteArray */ private function interleave(array $byteArray, int $maxBytes, int $numRsBlocks):void{ for($x = 0; $x < $maxBytes; $x++){ diff --git a/src/Decoder/Binarizer.php b/src/Decoder/Binarizer.php index 7b7b49f65..1e8d5e245 100644 --- a/src/Decoder/Binarizer.php +++ b/src/Decoder/Binarizer.php @@ -47,6 +47,7 @@ final class Binarizer{ private const LUMINANCE_BUCKETS = 32; private LuminanceSourceInterface $source; + /** @var int[] */ private array $luminances; /** @@ -58,6 +59,7 @@ final class Binarizer{ } /** + * @param int[] $buckets * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ private function estimateBlackPoint(array $buckets):int{ @@ -204,6 +206,8 @@ final class Binarizer{ * See the following thread for a discussion of this algorithm: * * @see http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0 + * + * @return float[][] */ private function calculateBlackPoints(int $subWidth, int $subHeight, int $width, int $height):array{ $blackPoints = array_fill(0, $subHeight, array_fill(0, $subWidth, 0)); diff --git a/src/Decoder/BitMatrix.php b/src/Decoder/BitMatrix.php index 2ec302a89..2f1bc6a91 100644 --- a/src/Decoder/BitMatrix.php +++ b/src/Decoder/BitMatrix.php @@ -105,6 +105,7 @@ final class BitMatrix extends QRMatrix{ * correct order in order to reconstruct the codewords bytes contained within the * QR Code. Throws if the exact number of bytes expected is not read. * + * @return int[] * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ public function readCodewords():array{ @@ -362,7 +363,6 @@ final class BitMatrix extends QRMatrix{ // Otherwise see if this is the closest to a real version info bit string // we have seen so far - /** @phan-suppress-next-line PhanTypeMismatchArgumentNullable ($targetVersionPattern is never null here) */ $bitsDifference = $this->numBitsDiffering($versionBits, $targetVersionPattern); if($bitsDifference < $bestDifference){ diff --git a/src/Decoder/DecoderResult.php b/src/Decoder/DecoderResult.php index 4b64b51f6..4790f42f2 100644 --- a/src/Decoder/DecoderResult.php +++ b/src/Decoder/DecoderResult.php @@ -40,6 +40,8 @@ final class DecoderResult{ /** * DecoderResult constructor. + * + * @phpstan-param array $properties */ public function __construct(iterable|null $properties = null){ diff --git a/src/Decoder/ReedSolomonDecoder.php b/src/Decoder/ReedSolomonDecoder.php index 2bd539aad..e3f61e653 100644 --- a/src/Decoder/ReedSolomonDecoder.php +++ b/src/Decoder/ReedSolomonDecoder.php @@ -47,6 +47,8 @@ final class ReedSolomonDecoder{ /** * Error-correct and copy data blocks together into a stream of bytes + * + * @param int[] $rawCodewords */ public function decode(array $rawCodewords):BitBuffer{ $dataBlocks = $this->deinterleaveRawBytes($rawCodewords); @@ -69,6 +71,8 @@ final class ReedSolomonDecoder{ * method will separate the data into original blocks. * * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException + * + * @param int[] $rawCodewords */ private function deinterleaveRawBytes(array $rawCodewords):array{ // Figure out the number and size of data blocks used by this version and @@ -87,7 +91,6 @@ final class ReedSolomonDecoder{ // All blocks have the same amount of data, except that the last n // (where n may be 0) have 1 more byte. Figure out where these start. - /** @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset */ $shorterBlocksTotalCodewords = count($result[0][1]); $longerBlocksStartAt = (count($result) - 1); @@ -120,7 +123,6 @@ final class ReedSolomonDecoder{ } // Now add in error correction blocks - /** @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset */ $max = count($result[0][1]); for($i = $shorterBlocksNumDataCodewords; $i < $max; $i++){ @@ -137,6 +139,9 @@ final class ReedSolomonDecoder{ /** * Given data and error-correction codewords received, possibly corrupted by errors, attempts to * correct the errors in-place using Reed-Solomon error correction. + * + * @param int[] $codewordBytes + * @return int[] */ private function correctErrors(array $codewordBytes, int $numDataCodewords):array{ // First read into an array of ints @@ -162,7 +167,7 @@ final class ReedSolomonDecoder{ * codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, * in the input. * - * @param array $received data and error-correction codewords + * @param int[] $received data and error-correction codewords * @param int $numEccCodewords number of error-correction codewords available * * @return int[] @@ -255,6 +260,7 @@ final class ReedSolomonDecoder{ } /** + * @return int[] * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ private function findErrorLocations(GenericGFPoly $errorLocator):array{ @@ -283,7 +289,8 @@ final class ReedSolomonDecoder{ } /** - * + * @param int[] $errorLocations + * @return int[] */ private function findErrorMagnitudes(GenericGFPoly $errorEvaluator, array $errorLocations):array{ // This is directly applying Forney's Formula diff --git a/src/Detector/AlignmentPatternFinder.php b/src/Detector/AlignmentPatternFinder.php index b4ee41fdf..812b823b6 100644 --- a/src/Detector/AlignmentPatternFinder.php +++ b/src/Detector/AlignmentPatternFinder.php @@ -61,6 +61,7 @@ final class AlignmentPatternFinder{ public function find(int $startX, int $startY, int $width, int $height):AlignmentPattern|null{ $maxJ = ($startX + $width); $middleI = ($startY + ($height / 2)); + /** @var int[] $stateCount */ $stateCount = []; // We are looking for black/white/black modules in 1:1:1 ratio; diff --git a/src/Detector/FinderPatternFinder.php b/src/Detector/FinderPatternFinder.php index 03de4a1a8..45bbe5407 100644 --- a/src/Detector/FinderPatternFinder.php +++ b/src/Detector/FinderPatternFinder.php @@ -7,8 +7,6 @@ * @author Smiley * @copyright 2021 Smiley * @license Apache-2.0 - * - * @phan-file-suppress PhanTypePossiblyInvalidDimOffset */ namespace chillerlan\QRCode\Detector; diff --git a/src/Detector/GridSampler.php b/src/Detector/GridSampler.php index 0d915e3e0..8c410ecef 100644 --- a/src/Detector/GridSampler.php +++ b/src/Detector/GridSampler.php @@ -30,6 +30,7 @@ use function array_fill, count, intdiv, sprintf; */ final class GridSampler{ + /** @var float[] */ private array $points; /** diff --git a/src/Detector/PerspectiveTransform.php b/src/Detector/PerspectiveTransform.php index ec4b2fba2..ba45e257a 100644 --- a/src/Detector/PerspectiveTransform.php +++ b/src/Detector/PerspectiveTransform.php @@ -150,7 +150,10 @@ final class PerspectiveTransform{ } /** - * @return array[] [$xValues, $yValues] + * @param float[] $xValues + * @param float[]|null $yValues + * + * @return float[][] [$xValues, $yValues] */ public function transformPoints(array $xValues, array|null $yValues = null):array{ $max = count($xValues); diff --git a/src/Output/CssColorModuleValueTrait.php b/src/Output/CssColorModuleValueTrait.php index 817ed7f13..a6514ad5c 100644 --- a/src/Output/CssColorModuleValueTrait.php +++ b/src/Output/CssColorModuleValueTrait.php @@ -21,11 +21,13 @@ trait CssColorModuleValueTrait{ * note: we're not necessarily validating the several values, just checking the general syntax * note: css4 colors are not included * + * implements \chillerlan\QRCode\Output\QROutputInterface::moduleValueIsValid() + * * @todo: XSS proof * * @see https://developer.mozilla.org/en-US/docs/Web/CSS/color_value - * @implements \chillerlan\QRCode\Output\QROutputInterface::moduleValueIsValid() - * @inheritDoc + * + * @param string $value */ public static function moduleValueIsValid(mixed $value):bool{ @@ -56,16 +58,16 @@ trait CssColorModuleValueTrait{ } /** - * @implements \chillerlan\QRCode\Output\QROutputAbstract::prepareModuleValue() - * @inheritDoc + * implements \chillerlan\QRCode\Output\QROutputAbstract::prepareModuleValue() + * + * @param string $value */ protected function prepareModuleValue(mixed $value):string{ return trim(strip_tags($value), " '\"\r\n\t"); } /** - * @implements \chillerlan\QRCode\Output\QROutputAbstract::getDefaultModuleValue() - * @inheritDoc + * implements \chillerlan\QRCode\Output\QROutputAbstract::getDefaultModuleValue() */ protected function getDefaultModuleValue(bool $isDark):string{ return ($isDark) ? '#000' : '#fff'; diff --git a/src/Output/QREps.php b/src/Output/QREps.php index 75f10ecdb..35a8c62f9 100644 --- a/src/Output/QREps.php +++ b/src/Output/QREps.php @@ -81,6 +81,8 @@ class QREps extends QROutputAbstract{ * 4 values in the color array will be interpreted as CMYK, 3 as RGB * * @throws \chillerlan\QRCode\Output\QRCodeOutputException + * + * @param float[] $values */ protected function formatColor(array $values):string{ $count = count($values); diff --git a/src/Output/QRFpdf.php b/src/Output/QRFpdf.php index 989724e4f..03d9bc1cb 100644 --- a/src/Output/QRFpdf.php +++ b/src/Output/QRFpdf.php @@ -30,6 +30,8 @@ class QRFpdf extends QROutputAbstract{ final public const MIME_TYPE = 'application/pdf'; protected FPDF $fpdf; + + /** @var int[] */ protected array|null $prevColor = null; /** @@ -71,7 +73,6 @@ class QRFpdf extends QROutputAbstract{ $bgColor = $this->prepareModuleValue($this->options->bgColor); [$width, $height] = $this->getOutputDimensions(); - /** @phan-suppress-next-line PhanParamTooFewUnpack */ $this->fpdf->SetFillColor(...$bgColor); $this->fpdf->Rect(0, 0, $width, $height, 'F'); } @@ -111,7 +112,6 @@ class QRFpdf extends QROutputAbstract{ $color = $this->getModuleValue($M_TYPE); if($color !== null && $color !== $this->prevColor){ - /** @phan-suppress-next-line PhanParamTooFewUnpack */ $this->fpdf->SetFillColor(...$color); $this->prevColor = $color; } diff --git a/src/Output/QRGdImage.php b/src/Output/QRGdImage.php index c695daf94..ccd10c78e 100644 --- a/src/Output/QRGdImage.php +++ b/src/Output/QRGdImage.php @@ -122,7 +122,6 @@ abstract class QRGdImage extends QROutputAbstract{ $values[] = max(0, min(255, intval($val))); } - /** @phan-suppress-next-line PhanParamTooFewInternalUnpack */ $color = imagecolorallocate($this->image, ...$values); if($color === false){ @@ -328,6 +327,7 @@ abstract class QRGdImage extends QROutputAbstract{ throw new QRCodeOutputException($exception->getMessage()); } + /** @var string $imageData */ return $imageData; } diff --git a/src/Output/QRMarkupXML.php b/src/Output/QRMarkupXML.php index cf0c7613a..7fc7922cb 100644 --- a/src/Output/QRMarkupXML.php +++ b/src/Output/QRMarkupXML.php @@ -8,7 +8,6 @@ * @license MIT * * @noinspection PhpComposerExtensionStubsInspection - * @phan-file-suppress PhanTypeMismatchArgumentInternal */ namespace chillerlan\QRCode\Output; @@ -29,6 +28,8 @@ class QRMarkupXML extends QRMarkup{ /** * @inheritDoc + * + * @return int[] */ protected function getOutputDimensions():array{ return [$this->moduleCount, $this->moduleCount]; @@ -53,8 +54,8 @@ class QRMarkupXML extends QRMarkup{ $root->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); $root->setAttribute('xsi:noNamespaceSchemaLocation', $this::SCHEMA); - $root->setAttribute('version', $this->matrix->getVersion()); - $root->setAttribute('eccLevel', $this->matrix->getEccLevel()); + $root->setAttribute('version', (string)$this->matrix->getVersion()); + $root->setAttribute('eccLevel', (string)$this->matrix->getEccLevel()); $root->appendChild($this->createMatrix()); $this->dom->appendChild($root); @@ -72,11 +73,11 @@ class QRMarkupXML extends QRMarkup{ $matrix = $this->dom->createElement('matrix'); $dimension = $this->matrix->getVersion()->getDimension(); - $matrix->setAttribute('size', $dimension); - $matrix->setAttribute('quietzoneSize', (int)(($this->moduleCount - $dimension) / 2)); - $matrix->setAttribute('maskPattern', $this->matrix->getMaskPattern()->getPattern()); - $matrix->setAttribute('width', $width); - $matrix->setAttribute('height', $height); + $matrix->setAttribute('size', (string)$dimension); + $matrix->setAttribute('quietzoneSize', (string)(int)(($this->moduleCount - $dimension) / 2)); + $matrix->setAttribute('maskPattern', (string)$this->matrix->getMaskPattern()->getPattern()); + $matrix->setAttribute('width', (string)$width); + $matrix->setAttribute('height', (string)$height); foreach($this->matrix->getMatrix() as $y => $row){ $matrixRow = $this->row($y, $row); @@ -91,11 +92,13 @@ class QRMarkupXML extends QRMarkup{ /** * Creates a DOM element for a matrix row + * + * @param int[] $row */ protected function row(int $y, array $row):DOMElement|null{ $matrixRow = $this->dom->createElement('row'); - $matrixRow->setAttribute('y', $y); + $matrixRow->setAttribute('y', (string)$y); foreach($row as $x => $M_TYPE){ $module = $this->module($x, $y, $M_TYPE); @@ -128,8 +131,9 @@ class QRMarkupXML extends QRMarkup{ $module->setAttribute('x', $x); $module->setAttribute('dark', ($isDark ? 'true' : 'false')); + $module->setAttribute('x', (string)$x); $module->setAttribute('layer', ($this::LAYERNAMES[$M_TYPE] ?? '')); - $module->setAttribute('value', $this->getModuleValue($M_TYPE)); + $module->setAttribute('value', (string)$this->getModuleValue($M_TYPE)); return $module; } diff --git a/src/Output/QROutputAbstract.php b/src/Output/QROutputAbstract.php index 9d1224958..76f97288d 100644 --- a/src/Output/QROutputAbstract.php +++ b/src/Output/QROutputAbstract.php @@ -35,6 +35,8 @@ abstract class QROutputAbstract implements QROutputInterface{ /** * an (optional) array of color values for the several QR matrix parts + * + * @phpstan-var array */ protected array $moduleValues; @@ -48,20 +50,26 @@ abstract class QROutputAbstract implements QROutputInterface{ */ protected SettingsContainerInterface|QROptions $options; + /** + * @see \chillerlan\QRCode\QROptions::$excludeFromConnect + * @var int[] + */ + protected array $excludeFromConnect; + /** + * @see \chillerlan\QRCode\QROptions::$keepAsSquare + * @var int[] + */ + protected array $keepAsSquare; /** @see \chillerlan\QRCode\QROptions::$scale */ protected int $scale; /** @see \chillerlan\QRCode\QROptions::$connectPaths */ protected bool $connectPaths; - /** @see \chillerlan\QRCode\QROptions::$excludeFromConnect */ - protected array $excludeFromConnect; /** @see \chillerlan\QRCode\QROptions::$eol */ protected string $eol; /** @see \chillerlan\QRCode\QROptions::$drawLightModules */ protected bool $drawLightModules; /** @see \chillerlan\QRCode\QROptions::$drawCircularModules */ protected bool $drawCircularModules; - /** @see \chillerlan\QRCode\QROptions::$keepAsSquare */ - protected array $keepAsSquare; /** @see \chillerlan\QRCode\QROptions::$circleRadius */ protected float $circleRadius; protected float $circleDiameter; @@ -122,6 +130,8 @@ abstract class QROutputAbstract implements QROutputInterface{ * Returns a 2 element array with the current output width and height * * The type and units of the values depend on the output class. The default value is the current module count * scale. + * + * @return int[] */ protected function getOutputDimensions():array{ return [$this->length, $this->length]; @@ -138,6 +148,7 @@ abstract class QROutputAbstract implements QROutputInterface{ } // now loop over the options values to replace defaults and add extra values + /** @var int $M_TYPE */ foreach($this->options->moduleValues as $M_TYPE => $value){ if($this::moduleValueIsValid($value)){ $this->moduleValues[$M_TYPE] = $this->prepareModuleValue($value); @@ -217,6 +228,8 @@ abstract class QROutputAbstract implements QROutputInterface{ * $y - current row * $M_TYPE - field value * $M_TYPE_LAYER - (possibly modified) field value that acts as layer id + * + * @return array */ protected function collectModules(Closure $transform):array{ $paths = []; diff --git a/src/Output/QRStringJSON.php b/src/Output/QRStringJSON.php index 05e580bb6..2e32aa9c9 100644 --- a/src/Output/QRStringJSON.php +++ b/src/Output/QRStringJSON.php @@ -15,7 +15,9 @@ namespace chillerlan\QRCode\Output; use function json_encode; /** + * @method string getModuleValue(int $M_TYPE) * + * @phpstan-type Module array{x: int, dark: bool, layer: string, value: string} */ class QRStringJSON extends QROutputAbstract{ use CssColorModuleValueTrait; @@ -25,6 +27,8 @@ class QRStringJSON extends QROutputAbstract{ /** * @inheritDoc + * + * @return int[] */ protected function getOutputDimensions():array{ return [$this->moduleCount, $this->moduleCount]; @@ -72,6 +76,9 @@ class QRStringJSON extends QROutputAbstract{ /** * Creates an array element for a matrix row + * + * @param int[] $row + * @phpstan-return array{y: int, modules: array} */ protected function row(int $y, array $row):array|null{ $matrixRow = ['y' => $y, 'modules' => []]; @@ -94,6 +101,8 @@ class QRStringJSON extends QROutputAbstract{ /** * Creates an array element for a single module + * + * @phpstan-return Module */ protected function module(int $x, int $y, int $M_TYPE):array|null{ $isDark = $this->matrix->isDark($M_TYPE); diff --git a/src/Output/QRStringText.php b/src/Output/QRStringText.php index 594e1d841..01df6423a 100644 --- a/src/Output/QRStringText.php +++ b/src/Output/QRStringText.php @@ -21,6 +21,8 @@ class QRStringText extends QROutputAbstract{ /** * @inheritDoc + * + * @param string $value */ public static function moduleValueIsValid(mixed $value):bool{ return is_string($value); @@ -28,6 +30,8 @@ class QRStringText extends QROutputAbstract{ /** * @inheritDoc + * + * @param string $value */ protected function prepareModuleValue(mixed $value):string{ return $value; diff --git a/src/Output/RGBArrayModuleValueTrait.php b/src/Output/RGBArrayModuleValueTrait.php index e7e73cd30..9c0138f74 100644 --- a/src/Output/RGBArrayModuleValueTrait.php +++ b/src/Output/RGBArrayModuleValueTrait.php @@ -18,8 +18,9 @@ use function array_values, count, intval, is_array, is_numeric, max, min; trait RGBArrayModuleValueTrait{ /** - * @implements \chillerlan\QRCode\Output\QROutputInterface::moduleValueIsValid() - * @inheritDoc + * implements \chillerlan\QRCode\Output\QROutputInterface::moduleValueIsValid() + * + * @param int[] $value */ public static function moduleValueIsValid(mixed $value):bool{ @@ -44,8 +45,11 @@ trait RGBArrayModuleValueTrait{ } /** - * @implements \chillerlan\QRCode\Output\QROutputAbstract::prepareModuleValue() - * @inheritDoc + * implements \chillerlan\QRCode\Output\QROutputAbstract::prepareModuleValue() + * + * @param int[] $value + * @return int[] + * * @throws \chillerlan\QRCode\Output\QRCodeOutputException */ protected function prepareModuleValue(mixed $value):array{ @@ -68,8 +72,9 @@ trait RGBArrayModuleValueTrait{ } /** - * @implements \chillerlan\QRCode\Output\QROutputAbstract::getDefaultModuleValue() - * @inheritDoc + * implements \chillerlan\QRCode\Output\QROutputAbstract::getDefaultModuleValue() + * + * @return int[] */ protected function getDefaultModuleValue(bool $isDark):array{ return ($isDark) ? [0, 0, 0] : [255, 255, 255]; diff --git a/src/QRCode.php b/src/QRCode.php index dc54558bc..da4ea14ba 100755 --- a/src/QRCode.php +++ b/src/QRCode.php @@ -51,6 +51,8 @@ class QRCode{ /** * QRCode constructor. + * + * @phpstan-param array $options */ public function __construct(SettingsContainerInterface|QROptions|iterable $options = new QROptions){ $this->setOptions($options); @@ -58,6 +60,8 @@ class QRCode{ /** * Sets an options instance + * + * @phpstan-param array $options */ public function setOptions(SettingsContainerInterface|QROptions|iterable $options):static{ @@ -80,7 +84,6 @@ class QRCode{ public function render(string|null $data = null, string|null $file = null):mixed{ if($data !== null){ - /** @var \chillerlan\QRCode\Data\QRDataModeInterface $dataInterface */ foreach(Mode::INTERFACES as $dataInterface){ if($dataInterface::validateString($data)){ @@ -157,7 +160,10 @@ class QRCode{ throw new QRCodeOutputException('output class does not implement QROutputInterface'); } - return new $outputInterface($this->options, $matrix); + /** @var \chillerlan\QRCode\Output\QROutputInterface $instance */ + $instance = new $outputInterface($this->options, $matrix); + + return $instance; } /** diff --git a/src/QRCodeReaderOptionsTrait.php b/src/QRCodeReaderOptionsTrait.php index 16b7da4be..b046b4984 100644 --- a/src/QRCodeReaderOptionsTrait.php +++ b/src/QRCodeReaderOptionsTrait.php @@ -14,6 +14,11 @@ use function extension_loaded; /** * Trait QRCodeReaderOptionsTrait + * + * @property bool $readerUseImagickIfAvailable + * @property bool $readerGrayscale + * @property bool $readerInvertColors + * @property bool $readerIncreaseContrast */ trait QRCodeReaderOptionsTrait{ diff --git a/src/QROptionsTrait.php b/src/QROptionsTrait.php index 49a8b05b2..aa5128cb6 100644 --- a/src/QROptionsTrait.php +++ b/src/QROptionsTrait.php @@ -22,6 +22,48 @@ use const JSON_THROW_ON_ERROR, JSON_UNESCAPED_SLASHES, PHP_EOL; /** * The QRCode plug-in settings & setter functionality + * + * @property int $version + * @property int $versionMin + * @property int $versionMax + * @property int $eccLevel + * @property int $maskPattern + * @property bool $addQuietzone + * @property int $quietzoneSize + * @property string $outputInterface + * @property bool $returnResource + * @property string|null $cachefile + * @property bool $outputBase64 + * @property string $eol + * @property mixed $bgColor + * @property bool $invertMatrix + * @property bool $drawLightModules + * @property bool $drawCircularModules + * @property float $circleRadius + * @property array $keepAsSquare + * @property bool $connectPaths + * @property array $excludeFromConnect + * @property array $moduleValues + * @property bool $addLogoSpace + * @property int|null $logoSpaceWidth + * @property int|null $logoSpaceHeight + * @property int|null $logoSpaceStartX + * @property int|null $logoSpaceStartY + * @property int $scale + * @property bool $imageTransparent + * @property mixed $transparencyColor + * @property int $quality + * @property bool $gdImageUseUpscale + * @property string $imagickFormat + * @property string $cssClass + * @property bool $svgAddXmlHeader + * @property string $svgDefs + * @property string $svgPreserveAspectRatio + * @property bool $svgUseFillAttributes + * @property string $textLineStart + * @property int $jsonFlags + * @property string $fpdfMeasureUnit + * @property string|null $xmlStylesheet */ trait QROptionsTrait{ @@ -143,6 +185,7 @@ trait QROptionsTrait{ */ protected string $eol = PHP_EOL; + /* * Common visual modifications */ @@ -199,6 +242,8 @@ trait QROptionsTrait{ * Specifies which module types to exclude when `QROptions::$drawCircularModules` is set to `true` * * (default: `[]`) + * + * @var int[] */ protected array $keepAsSquare = []; @@ -222,6 +267,8 @@ trait QROptionsTrait{ * Specify which paths/patterns to exclude from connecting if `QROptions::$connectPaths` is set to `true` * * @see \chillerlan\QRCode\QROptionsTrait::$connectPaths + * + * @var int[] */ protected array $excludeFromConnect = []; @@ -233,6 +280,8 @@ trait QROptionsTrait{ * - `QREps`: `[C, M, Y, K]` // 0-255 * * @see \chillerlan\QRCode\Output\QROutputAbstract::setModuleValues() + * + * @var array */ protected array $moduleValues = []; @@ -321,6 +370,7 @@ trait QROptionsTrait{ */ protected int $quality = -1; + /* * QRGdImage settings */ @@ -334,6 +384,7 @@ trait QROptionsTrait{ */ protected bool $gdImageUseUpscale = true; + /* * QRImagick settings */ @@ -356,6 +407,7 @@ trait QROptionsTrait{ */ protected string $cssClass = 'qrcode'; + /* * QRMarkupSVG settings */ @@ -391,6 +443,7 @@ trait QROptionsTrait{ */ protected bool $svgUseFillAttributes = true; + /* * QRStringText settings */ @@ -400,6 +453,7 @@ trait QROptionsTrait{ */ protected string $textLineStart = ''; + /* * QRStringJSON settings */ @@ -411,6 +465,7 @@ trait QROptionsTrait{ */ protected int $jsonFlags = JSON_THROW_ON_ERROR|JSON_UNESCAPED_SLASHES; + /* * QRFpdf settings */ @@ -422,6 +477,7 @@ trait QROptionsTrait{ */ protected string $fpdfMeasureUnit = 'pt'; + /* * QRMarkupXML settings */ @@ -485,6 +541,7 @@ trait QROptionsTrait{ $eccLevel = constant(EccLevel::class.'::'.$ecc); } + /** @var int $eccLevel */ if((0b11 & $eccLevel) !== $eccLevel){ throw new QRCodeException(sprintf('Invalid ECC level: "%s"', $eccLevel)); } diff --git a/tests/Common/BitBufferTest.php b/tests/Common/BitBufferTest.php index 7a38d1e5b..e4ae40f8e 100644 --- a/tests/Common/BitBufferTest.php +++ b/tests/Common/BitBufferTest.php @@ -26,6 +26,9 @@ final class BitBufferTest extends TestCase{ $this->bitBuffer = new BitBuffer; } + /** + * @phpstan-return array + */ public static function bitProvider():array{ return [ 'number' => [Mode::NUMBER, 16], diff --git a/tests/Common/ECICharsetTest.php b/tests/Common/ECICharsetTest.php index 726102ae7..c47c3cea0 100644 --- a/tests/Common/ECICharsetTest.php +++ b/tests/Common/ECICharsetTest.php @@ -17,6 +17,9 @@ use PHPUnit\Framework\TestCase; final class ECICharsetTest extends TestCase{ + /** + * @phpstan-return array + */ public static function invalidIdProvider():array{ return [[-1], [1000000]]; } @@ -25,10 +28,13 @@ final class ECICharsetTest extends TestCase{ public function testInvalidDataException(int $id):void{ $this->expectException(QRCodeException::class); $this->expectExceptionMessage('invalid charset id:'); - /** @phan-suppress-next-line PhanNoopNew */ + new ECICharset($id); } + /** + * @phpstan-return array + */ public static function encodingProvider():array{ $params = []; diff --git a/tests/Common/EccLevelTest.php b/tests/Common/EccLevelTest.php index eec7422ad..3ad207a90 100644 --- a/tests/Common/EccLevelTest.php +++ b/tests/Common/EccLevelTest.php @@ -22,7 +22,7 @@ final class EccLevelTest extends TestCase{ public function testConstructInvalidEccException():void{ $this->expectException(QRCodeException::class); $this->expectExceptionMessage('invalid ECC level'); - /** @phan-suppress-next-line PhanNoopNew */ + new EccLevel(69); } diff --git a/tests/Common/MaskPatternTest.php b/tests/Common/MaskPatternTest.php index 185b9a60e..0fc099ce1 100644 --- a/tests/Common/MaskPatternTest.php +++ b/tests/Common/MaskPatternTest.php @@ -123,7 +123,7 @@ final class MaskPatternTest extends TestCase{ public function testInvalidMaskPatternException():void{ $this->expectException(QRCodeException::class); $this->expectExceptionMessage('invalid mask pattern'); - /** @phan-suppress-next-line PhanNoopNew */ + new MaskPattern(42); } diff --git a/tests/Common/ModeTest.php b/tests/Common/ModeTest.php index 3e7b2f211..7e533555a 100644 --- a/tests/Common/ModeTest.php +++ b/tests/Common/ModeTest.php @@ -22,6 +22,8 @@ final class ModeTest extends TestCase{ /** * version breakpoints for numeric mode + * + * @phpstan-return array */ public static function versionProvider():array{ return [ @@ -42,14 +44,14 @@ final class ModeTest extends TestCase{ public function testGetLengthBitsForVersionInvalidModeException():void{ $this->expectException(QRCodeException::class); $this->expectExceptionMessage('invalid mode given'); - /** @phan-suppress-next-line PhanNoopNew */ + Mode::getLengthBitsForVersion(42, 69); } public function testGetLengthBitsForVersionInvalidVersionException():void{ $this->expectException(QRCodeException::class); $this->expectExceptionMessage('invalid version number'); - /** @phan-suppress-next-line PhanNoopNew */ + Mode::getLengthBitsForVersion(Mode::BYTE, 69); } diff --git a/tests/Common/VersionTest.php b/tests/Common/VersionTest.php index 3b6196cbc..2069ac66e 100644 --- a/tests/Common/VersionTest.php +++ b/tests/Common/VersionTest.php @@ -58,7 +58,7 @@ final class VersionTest extends TestCase{ public function testConstructInvalidVersion():void{ $this->expectException(QRCodeException::class); $this->expectExceptionMessage('invalid version given'); - /** @phan-suppress-next-line PhanNoopNew */ + new Version(69); } diff --git a/tests/Data/AlphaNumTest.php b/tests/Data/AlphaNumTest.php index f6c83868d..2050faa78 100644 --- a/tests/Data/AlphaNumTest.php +++ b/tests/Data/AlphaNumTest.php @@ -26,6 +26,8 @@ final class AlphaNumTest extends DataInterfaceTestAbstract{ /** * isAlphaNum() should pass on the 45 defined characters and fail on anything else (e.g. lowercase) + * + * @phpstan-return array */ public static function stringValidateProvider():array{ return [ diff --git a/tests/Data/ByteTest.php b/tests/Data/ByteTest.php index 4aaf64d0b..0ec9708d0 100644 --- a/tests/Data/ByteTest.php +++ b/tests/Data/ByteTest.php @@ -26,6 +26,8 @@ final class ByteTest extends DataInterfaceTestAbstract{ /** * isByte() passses any binary string and only fails on empty strings + * + * @phpstan-return array */ public static function stringValidateProvider():array{ return [ diff --git a/tests/Data/DataInterfaceTestAbstract.php b/tests/Data/DataInterfaceTestAbstract.php index 79fdbf673..4ff7d5867 100644 --- a/tests/Data/DataInterfaceTestAbstract.php +++ b/tests/Data/DataInterfaceTestAbstract.php @@ -60,6 +60,9 @@ abstract class DataInterfaceTestAbstract extends TestCase{ $this::assertSame($pattern, $matrix->getMaskPattern()->getPattern()); } + /** + * @phpstan-return array + */ abstract public static function stringValidateProvider():array; /** @@ -81,6 +84,8 @@ abstract class DataInterfaceTestAbstract extends TestCase{ /** * returns versions within the version breakpoints 1-9, 10-26 and 27-40 + * + * @phpstan-return array */ public static function versionBreakpointProvider():array{ return ['1-9' => [7], '10-26' => [15], '27-40' => [30]]; @@ -118,7 +123,7 @@ abstract class DataInterfaceTestAbstract extends TestCase{ public static function maxLengthProvider():Generator{ $eccLevels = array_map(fn(int $ecc):EccLevel => new EccLevel($ecc), [EccLevel::L, EccLevel::M, EccLevel::Q, EccLevel::H]); $str = str_repeat(static::testData, 1000); - /** @phan-suppress-next-line PhanAbstractStaticMethodCallInStatic */ + $dataMode = static::getDataModeInterface(static::testData)::DATAMODE; $mb = ($dataMode === Mode::KANJI || $dataMode === Mode::HANZI); @@ -203,7 +208,7 @@ abstract class DataInterfaceTestAbstract extends TestCase{ $options->version = $version->getVersionNumber(); $options->eccLevel = $eccLevel->getLevel(); - /** @phan-suppress-next-line PhanNoopNew */ + new QRData($options, [static::getDataModeInterface($str1)]); } diff --git a/tests/Data/ECITest.php b/tests/Data/ECITest.php index 7130e4f23..c19f4154c 100644 --- a/tests/Data/ECITest.php +++ b/tests/Data/ECITest.php @@ -30,10 +30,12 @@ final class ECITest extends TestCase{ $this->QRData = new QRData(new QROptions); } + /** + * @phpstan-return array{0: ECI, 1: Byte} + */ private function getDataSegments():array{ return [ new ECI($this->testCharset), - /** @phan-suppress-next-line PhanParamSuspiciousOrder */ new Byte(mb_convert_encoding(self::testData, ECICharset::MB_ENCODINGS[$this->testCharset], mb_internal_encoding())), ]; } @@ -46,6 +48,8 @@ final class ECITest extends TestCase{ /** * returns versions within the version breakpoints 1-9, 10-26 and 27-40 + * + * @phpstan-return array */ public static function versionBreakpointProvider():array{ return ['1-9' => [7], '10-26' => [15], '27-40' => [30]]; @@ -72,7 +76,7 @@ final class ECITest extends TestCase{ public function testInvalidDataException():void{ $this->expectException(QRCodeDataException::class); $this->expectExceptionMessage('invalid encoding id:'); - /** @phan-suppress-next-line PhanNoopNew */ + new ECI(-1); } @@ -83,10 +87,13 @@ final class ECITest extends TestCase{ public function testInvalidDataOnEmptyException():void{ $this->expectException(QRCodeDataException::class); $this->expectExceptionMessage('invalid encoding id:'); - /** @phan-suppress-next-line PhanNoopNew */ + new ECI(1000000); } + /** + * @phpstan-return array + */ public static function eciCharsetIdProvider():array{ return [ [ 0, 8], @@ -129,6 +136,9 @@ final class ECITest extends TestCase{ ECI::decodeSegment($bitBuffer, $options->version); } + /** + * @phpstan-return array + */ public static function unknownEncodingDataProvider():array{ return [ 'CP437' => [0, "\x41\x42\x43"], diff --git a/tests/Data/HanziTest.php b/tests/Data/HanziTest.php index aff1ec462..9fc77ebc7 100644 --- a/tests/Data/HanziTest.php +++ b/tests/Data/HanziTest.php @@ -30,6 +30,8 @@ final class HanziTest extends DataInterfaceTestAbstract{ /** * isGB2312() should pass on Hanzi/GB2312 characters and fail on everything else + * + * @phpstan-return array */ public static function stringValidateProvider():array{ return [ diff --git a/tests/Data/KanjiTest.php b/tests/Data/KanjiTest.php index a972dc2a9..09942df17 100644 --- a/tests/Data/KanjiTest.php +++ b/tests/Data/KanjiTest.php @@ -30,6 +30,8 @@ final class KanjiTest extends DataInterfaceTestAbstract{ /** * isKanji() should pass on Kanji/SJIS characters and fail on everything else + * + * @phpstan-return array */ public static function stringValidateProvider():array{ return [ diff --git a/tests/Data/NumberTest.php b/tests/Data/NumberTest.php index aace881f3..b48d39878 100644 --- a/tests/Data/NumberTest.php +++ b/tests/Data/NumberTest.php @@ -26,6 +26,8 @@ final class NumberTest extends DataInterfaceTestAbstract{ /** * isNumber() should pass on any number and fail on anything else + * + * @phpstan-return array */ public static function stringValidateProvider():array{ return [ diff --git a/tests/Output/CssColorModuleValueProviderTrait.php b/tests/Output/CssColorModuleValueProviderTrait.php index 52ee60ad5..eae2dbea2 100644 --- a/tests/Output/CssColorModuleValueProviderTrait.php +++ b/tests/Output/CssColorModuleValueProviderTrait.php @@ -17,9 +17,6 @@ namespace chillerlan\QRCodeTest\Output; */ trait CssColorModuleValueProviderTrait{ - /** - * @implements \chillerlan\QRCodeTest\Output\QROutputTestAbstract::moduleValueProvider() - */ public static function moduleValueProvider():array{ return [ 'invalid: wrong type' => [[], false], diff --git a/tests/Output/QREpsTest.php b/tests/Output/QREpsTest.php index 82905912f..5b546bd4b 100644 --- a/tests/Output/QREpsTest.php +++ b/tests/Output/QREpsTest.php @@ -50,6 +50,7 @@ class QREpsTest extends QROutputTestAbstract{ $this->outputInterface = $this->getOutputInterface($this->options, $this->matrix); $this->outputInterface->dump(); + /** @phpstan-ignore-next-line */ $this::assertTrue(true); // tricking the code coverage } diff --git a/tests/Output/QRFpdfTest.php b/tests/Output/QRFpdfTest.php index 03d5e7638..e01fcff8d 100644 --- a/tests/Output/QRFpdfTest.php +++ b/tests/Output/QRFpdfTest.php @@ -56,6 +56,7 @@ final class QRFpdfTest extends QROutputTestAbstract{ $this->outputInterface = $this->getOutputInterface($this->options, $this->matrix); $this->outputInterface->dump(); + /** @phpstan-ignore-next-line */ $this::assertTrue(true); // tricking the code coverage } diff --git a/tests/Output/QRGdImageAVIFTest.php b/tests/Output/QRGdImageAVIFTest.php index 13dbbf377..a4568ab9b 100644 --- a/tests/Output/QRGdImageAVIFTest.php +++ b/tests/Output/QRGdImageAVIFTest.php @@ -8,11 +8,10 @@ * @license MIT */ -namespace Output; +namespace chillerlan\QRCodeTest\Output; use chillerlan\QRCode\QROptions; use chillerlan\QRCode\Data\QRMatrix; -use chillerlan\QRCodeTest\Output\QRGdImageTestAbstract; use chillerlan\QRCode\Output\{QRGdImageAVIF, QROutputInterface}; use chillerlan\Settings\SettingsContainerInterface; diff --git a/tests/Output/QRGdImageTestAbstract.php b/tests/Output/QRGdImageTestAbstract.php index c79397e67..f5fd46ae3 100644 --- a/tests/Output/QRGdImageTestAbstract.php +++ b/tests/Output/QRGdImageTestAbstract.php @@ -48,6 +48,7 @@ abstract class QRGdImageTestAbstract extends QROutputTestAbstract{ $this->outputInterface = $this->getOutputInterface($this->options, $this->matrix); $this->outputInterface->dump(); + /** @phpstan-ignore-next-line */ $this::assertTrue(true); // tricking the code coverage } diff --git a/tests/Output/QRImagickTest.php b/tests/Output/QRImagickTest.php index 5a33e25bc..2d4ca3e44 100644 --- a/tests/Output/QRImagickTest.php +++ b/tests/Output/QRImagickTest.php @@ -83,6 +83,7 @@ final class QRImagickTest extends QROutputTestAbstract{ $this->outputInterface = $this->getOutputInterface($this->options, $this->matrix); $this->outputInterface->dump(); + /** @phpstan-ignore-next-line */ $this::assertTrue(true); // tricking the code coverage } diff --git a/tests/Output/QRInterventionImageTest.php b/tests/Output/QRInterventionImageTest.php index eac185a6c..81bd0b018 100644 --- a/tests/Output/QRInterventionImageTest.php +++ b/tests/Output/QRInterventionImageTest.php @@ -57,6 +57,7 @@ class QRInterventionImageTest extends QROutputTestAbstract{ $this->outputInterface = $this->getOutputInterface($this->options, $this->matrix); $this->outputInterface->dump(); + /** @phpstan-ignore-next-line */ $this::assertTrue(true); // tricking the code coverage } diff --git a/tests/Output/QROutputTestAbstract.php b/tests/Output/QROutputTestAbstract.php index 568bcad3a..27367d2f2 100644 --- a/tests/Output/QROutputTestAbstract.php +++ b/tests/Output/QROutputTestAbstract.php @@ -58,6 +58,9 @@ abstract class QROutputTestAbstract extends TestCase{ $this->outputInterface->dump('/foo/bar.test'); } + /** + * @phpstan-return array + */ abstract public static function moduleValueProvider():array; #[DataProvider('moduleValueProvider')] diff --git a/tests/Output/QRStringTextTest.php b/tests/Output/QRStringTextTest.php index 9ce58455c..ead032c8b 100644 --- a/tests/Output/QRStringTextTest.php +++ b/tests/Output/QRStringTextTest.php @@ -27,6 +27,9 @@ final class QRStringTextTest extends QROutputTestAbstract{ return new QRStringText($options, $matrix); } + /** + * @phpstan-return array + */ public static function moduleValueProvider():array{ return [ 'invalid: wrong type' => [[], false], diff --git a/tests/QRCodeReaderImagickTest.php b/tests/QRCodeReaderImagickTest.php index c8d2d412d..5056f3535 100644 --- a/tests/QRCodeReaderImagickTest.php +++ b/tests/QRCodeReaderImagickTest.php @@ -41,6 +41,9 @@ final class QRCodeReaderImagickTest extends QRCodeReaderTestAbstract{ return IMagickLuminanceSource::fromFile($file, $options); } + /** + * @phpstan-return array + */ public static function vectorQRCodeProvider():array{ return [ // SVG convert only works on windows (Warning: Option --export-png= is deprecated) diff --git a/tests/QRCodeReaderTestAbstract.php b/tests/QRCodeReaderTestAbstract.php index 0da27f53a..a0e23e698 100644 --- a/tests/QRCodeReaderTestAbstract.php +++ b/tests/QRCodeReaderTestAbstract.php @@ -51,6 +51,9 @@ abstract class QRCodeReaderTestAbstract extends TestCase{ $this->options->readerUseImagickIfAvailable = false; } + /** + * @phpstan-return array + */ public static function qrCodeProvider():array{ return [ 'helloworld' => ['hello_world.png', 'Hello world!', false], @@ -129,7 +132,7 @@ abstract class QRCodeReaderTestAbstract extends TestCase{ /** * @noinspection PhpUndefinedConstantInspection - see phpunit.xml.dist - * @phan-suppress-next-next-line PhanUndeclaredConstant + * @phpstan-ignore-next-line */ for($v = 1; $v <= READER_TEST_MAX_VERSION; $v++){ $version = new Version($v); diff --git a/tests/QROptionsTest.php b/tests/QROptionsTest.php index 21ce28aa9..bfcde1614 100644 --- a/tests/QROptionsTest.php +++ b/tests/QROptionsTest.php @@ -74,7 +74,7 @@ final class QROptionsTest extends TestCase{ $o = new QROptions(['eccLevel' => EccLevel::H]); $this::assertSame(EccLevel::H, $o->eccLevel); - + /** @phpstan-ignore-next-line */ $o->eccLevel = 'q'; $this::assertSame(EccLevel::Q, $o->eccLevel); @@ -86,7 +86,7 @@ final class QROptionsTest extends TestCase{ public function testSetEccLevelFromIntException():void{ $this->expectException(QRCodeException::class); $this->expectExceptionMessage('Invalid ECC level: "42"'); - /** @phan-suppress-next-line PhanNoopNew */ + new QROptions(['eccLevel' => 42]); } @@ -96,7 +96,7 @@ final class QROptionsTest extends TestCase{ public function testSetEccLevelFromStringException():void{ $this->expectException(QRCodeException::class); $this->expectExceptionMessage('Invalid ECC level: "FOO"'); - /** @phan-suppress-next-line PhanNoopNew */ + new QROptions(['eccLevel' => 'foo']); }