From 7b5ad92e66d80ce23ffed4fc3bbe1512b8be9467 Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Mon, 29 May 2023 16:21:31 +0900 Subject: [PATCH] Composer updates --- composer.json | 3 +- composer.lock | 241 +++--- vendor/composer/installed.json | 159 ++-- vendor/composer/installed.php | 70 +- .../jsonmapper/.github/workflows/test.yml | 46 + .../netresearch/jsonmapper/src/JsonMapper.php | 70 +- .../lib/PhpParser/Builder/Param.php | 48 +- vendor/phpstan/extension-installer/README.md | 16 + .../build-cs/composer.json | 7 +- .../build-cs/composer.lock | 119 +-- .../phpstan/extension-installer/composer.json | 2 +- .../src/GeneratedConfig.php | 27 +- .../extension-installer/src/Plugin.php | 23 + vendor/phpstan/phpdoc-parser/README.md | 96 ++- vendor/phpstan/phpdoc-parser/composer.json | 1 + .../phpdoc-parser/phpstan-baseline.neon | 31 + .../src/Ast/AbstractNodeVisitor.php | 34 + .../phpdoc-parser/src/Ast/Attribute.php | 16 + .../QuoteAwareConstExprStringNode.php | 78 ++ .../phpdoc-parser/src/Ast/NodeTraverser.php | 312 +++++++ .../phpdoc-parser/src/Ast/NodeVisitor.php | 87 ++ .../src/Ast/NodeVisitor/CloningVisitor.php | 20 + .../src/Ast/PhpDoc/InvalidTagValueNode.php | 3 +- .../src/Ast/PhpDoc/MethodTagValueNode.php | 4 + .../src/Ast/Type/ArrayShapeNode.php | 1 + .../src/Ast/Type/ArrayTypeNode.php | 8 + .../src/Ast/Type/CallableTypeNode.php | 9 +- .../Ast/Type/CallableTypeParameterNode.php | 4 +- .../src/Ast/Type/GenericTypeNode.php | 4 + .../src/Ast/Type/IntersectionTypeNode.php | 12 +- .../src/Ast/Type/InvalidTypeNode.php | 38 + .../src/Ast/Type/ObjectShapeItemNode.php | 48 ++ .../src/Ast/Type/ObjectShapeNode.php | 31 + .../src/Ast/Type/OffsetAccessTypeNode.php | 8 + .../src/Ast/Type/UnionTypeNode.php | 12 +- .../phpstan/phpdoc-parser/src/Lexer/Lexer.php | 19 +- .../src/Parser/ConstExprParser.php | 225 +++-- .../src/Parser/ParserException.php | 21 +- .../phpdoc-parser/src/Parser/PhpDocParser.php | 164 +++- .../src/Parser/StringUnescaper.php | 96 +++ .../src/Parser/TokenIterator.php | 111 ++- .../phpdoc-parser/src/Parser/TypeParser.php | 385 ++++++++- .../phpdoc-parser/src/Printer/DiffElem.php | 44 + .../phpdoc-parser/src/Printer/Differ.php | 196 +++++ .../phpdoc-parser/src/Printer/Printer.php | 796 +++++++++++++++++ vendor/phpstan/phpstan/bootstrap.php | 1 - vendor/phpstan/phpstan/phpstan.phar | Bin 21593272 -> 21742779 bytes vendor/phpstan/phpstan/phpstan.phar.asc | 26 +- vendor/sebastian/diff/ChangeLog.md | 14 + vendor/sebastian/diff/README.md | 2 + vendor/sebastian/diff/SECURITY.md | 6 +- vendor/sebastian/diff/src/Differ.php | 12 +- vendor/sebastian/diff/src/Line.php | 6 +- ...ientLongestCommonSubsequenceCalculator.php | 7 +- ...ientLongestCommonSubsequenceCalculator.php | 24 +- vendor/spatie/array-to-xml/CHANGELOG.md | 17 + vendor/spatie/array-to-xml/README.md | 3 - vendor/spatie/array-to-xml/src/ArrayToXml.php | 13 +- .../console/Command/CompleteCommand.php | 4 +- .../console/Command/DumpCompletionCommand.php | 29 +- .../Formatter/OutputFormatterStyle.php | 3 +- .../symfony/console/Helper/QuestionHelper.php | 17 +- vendor/symfony/console/Helper/Table.php | 2 +- .../symfony/console/Input/InputArgument.php | 2 +- .../symfony/console/Resources/completion.zsh | 2 + vendor/symfony/console/Terminal.php | 17 +- vendor/symfony/console/composer.json | 2 +- vendor/symfony/filesystem/Filesystem.php | 2 +- .../string/Inflector/EnglishInflector.php | 6 + vendor/vimeo/psalm/composer.json | 1 + vendor/vimeo/psalm/config.xsd | 3 + vendor/vimeo/psalm/dictionaries/CallMap.php | 333 ++++--- .../psalm/dictionaries/CallMap_71_delta.php | 6 +- .../psalm/dictionaries/CallMap_72_delta.php | 4 +- .../psalm/dictionaries/CallMap_73_delta.php | 14 +- .../psalm/dictionaries/CallMap_80_delta.php | 94 +- .../psalm/dictionaries/CallMap_81_delta.php | 12 +- .../psalm/dictionaries/CallMap_82_delta.php | 10 +- .../psalm/dictionaries/CallMap_historical.php | 315 +++---- .../annotating_code/supported_annotations.md | 114 ++- .../type_syntax/array_types.md | 11 + .../type_syntax/atomic_types.md | 2 +- .../type_syntax/utility_types.md | 18 +- .../psalm/docs/running_psalm/configuration.md | 9 + .../vimeo/psalm/docs/running_psalm/issues.md | 2 + .../issues/InheritorViolation.md | 17 + .../issues/InvalidExtendClass.md | 11 +- .../docs/running_psalm/issues/TaintedHtml.md | 1 + .../issues/TaintedTextWithQuotes.md | 1 + .../psalm/docs/running_psalm/issues/Trace.md | 3 +- .../UnsupportedPropertyReferenceUsage.md | 40 + .../avoiding_false_positives.md | 19 +- vendor/vimeo/psalm/src/Psalm/CodeLocation.php | 1 + vendor/vimeo/psalm/src/Psalm/Codebase.php | 458 +++++++++- vendor/vimeo/psalm/src/Psalm/Config.php | 11 +- .../psalm/src/Psalm/Config/FileFilter.php | 2 + vendor/vimeo/psalm/src/Psalm/DocComment.php | 3 +- .../vimeo/psalm/src/Psalm/ErrorBaseline.php | 2 +- .../Psalm/Internal/Analyzer/ClassAnalyzer.php | 14 +- .../Internal/Analyzer/ClassLikeAnalyzer.php | 24 +- .../Analyzer/FunctionLikeAnalyzer.php | 227 +++-- .../Internal/Analyzer/NamespaceAnalyzer.php | 7 +- .../Internal/Analyzer/ProjectAnalyzer.php | 140 +-- .../Statements/Block/ForeachAnalyzer.php | 8 +- .../Statements/Block/IfElse/ElseAnalyzer.php | 2 +- .../Statements/Block/LoopAnalyzer.php | 5 - .../Statements/Expression/ArrayAnalyzer.php | 33 +- .../Expression/ArrayCreationInfo.php | 7 +- .../InstancePropertyAssignmentAnalyzer.php | 2 +- .../Expression/AssignmentAnalyzer.php | 11 +- .../Expression/Call/ArgumentAnalyzer.php | 6 +- .../Expression/Call/ArgumentsAnalyzer.php | 210 +---- .../Call/ArrayFunctionArgumentsAnalyzer.php | 212 ++++- .../Expression/Call/FunctionCallAnalyzer.php | 13 +- .../Call/FunctionCallReturnTypeFetcher.php | 16 +- .../Call/HighOrderFunctionArgHandler.php | 325 +++++++ .../Call/HighOrderFunctionArgInfo.php | 90 ++ .../Call/Method/AtomicMethodCallAnalyzer.php | 65 ++ .../ExistingAtomicMethodCallAnalyzer.php | 60 +- .../Call/Method/MissingMethodCallHandler.php | 2 +- .../Expression/Call/NewAnalyzer.php | 98 ++- .../ExistingAtomicStaticCallAnalyzer.php | 109 ++- .../Statements/Expression/CallAnalyzer.php | 2 + .../Expression/ClassConstAnalyzer.php | 1 + .../Statements/Expression/EvalAnalyzer.php | 3 + .../Fetch/AtomicPropertyFetchAnalyzer.php | 135 ++- .../Statements/Expression/IncludeAnalyzer.php | 15 +- .../Statements/Expression/MatchAnalyzer.php | 33 +- .../Expression/SimpleTypeInferer.php | 18 +- .../Statements/ExpressionAnalyzer.php | 79 +- .../Internal/Analyzer/StatementsAnalyzer.php | 1 + .../src/Psalm/Internal/Cli/LanguageServer.php | 168 ++-- .../psalm/src/Psalm/Internal/Cli/Psalm.php | 37 +- .../psalm/src/Psalm/Internal/Cli/Psalter.php | 15 +- .../psalm/src/Psalm/Internal/CliUtils.php | 48 +- .../ClassConstantByWildcardResolver.php | 33 +- .../Psalm/Internal/Codebase/ClassLikes.php | 181 +++- .../Codebase/ConstantTypeResolver.php | 21 + .../src/Psalm/Internal/Codebase/Methods.php | 2 - .../src/Psalm/Internal/Codebase/Populator.php | 8 +- .../src/Psalm/Internal/Codebase/Scanner.php | 1 + .../Codebase/StorageByPatternResolver.php | 87 ++ .../src/Psalm/Internal/EventDispatcher.php | 24 + .../FunctionDocblockManipulator.php | 2 +- .../Psalm/Internal/Fork/PsalmRestarter.php | 3 + .../LanguageServer/Client/TextDocument.php | 52 +- .../LanguageServer/Client/Workspace.php | 59 ++ .../LanguageServer/ClientConfiguration.php | 129 +++ .../Internal/LanguageServer/ClientHandler.php | 2 - .../LanguageServer/LanguageClient.php | 172 +++- .../LanguageServer/LanguageServer.php | 814 ++++++++++++++---- .../Psalm/Internal/LanguageServer/Message.php | 7 +- .../LanguageServer/PHPMarkdownContent.php | 58 ++ .../Internal/LanguageServer/Progress.php | 35 + .../LanguageServer/ProtocolStreamReader.php | 4 +- .../ClassLikeStorageCacheProvider.php | 47 + .../Provider/FileReferenceCacheProvider.php | 280 ++++++ .../Provider/FileStorageCacheProvider.php | 48 ++ .../Provider/ParserCacheProvider.php | 109 +++ .../Provider/ProjectCacheProvider.php | 41 + .../Internal/LanguageServer/Reference.php | 22 + .../LanguageServer/Server/TextDocument.php | 377 ++++---- .../LanguageServer/Server/Workspace.php | 94 +- .../Reflector/ClassLikeDocblockParser.php | 24 + .../Reflector/ClassLikeNodeScanner.php | 52 +- .../Reflector/ExpressionResolver.php | 21 + .../Reflector/FunctionLikeDocblockScanner.php | 14 +- .../Internal/PhpVisitor/ReflectorVisitor.php | 6 + .../Provider/ClassLikeStorageProvider.php | 4 + .../Internal/Provider/FakeFileProvider.php | 16 +- .../Psalm/Internal/Provider/FileProvider.php | 55 +- .../Provider/FunctionReturnTypeProvider.php | 6 +- .../ArrayUniqueReturnTypeProvider.php | 60 -- .../DateReturnTypeProvider.php | 69 ++ .../PowReturnTypeProvider.php | 92 ++ .../Scanner/ClassLikeDocblockComment.php | 6 +- .../UnresolvedConstant/EnumNameFetch.php | 11 + .../UnresolvedConstant/EnumPropertyFetch.php | 22 + .../UnresolvedConstant/EnumValueFetch.php | 11 + .../src/Psalm/Internal/Type/ArrayType.php | 27 +- .../Type/Comparator/AtomicTypeComparator.php | 75 +- .../Comparator/ClassLikeStringComparator.php | 13 +- .../Type/Comparator/KeyedArrayComparator.php | 277 +++++- .../Type/Comparator/ObjectComparator.php | 11 +- .../Type/Comparator/UnionTypeComparator.php | 7 +- .../Type/NegatedAssertionReconciler.php | 4 + .../Psalm/Internal/Type/ParseTreeCreator.php | 28 +- .../Type/SimpleAssertionReconciler.php | 81 +- .../Type/TemplateStandinTypeReplacer.php | 70 +- .../src/Psalm/Internal/Type/TypeCombiner.php | 22 +- .../src/Psalm/Internal/Type/TypeExpander.php | 92 +- .../src/Psalm/Internal/Type/TypeParser.php | 441 +++++++--- .../src/Psalm/Internal/Type/TypeTokenizer.php | 2 +- .../src/Psalm/Issue/InheritorViolation.php | 9 + .../UnsupportedPropertyReferenceUsage.php | 21 + vendor/vimeo/psalm/src/Psalm/IssueBuffer.php | 2 +- .../BeforeExpressionAnalysisInterface.php | 15 + .../Event/BeforeExpressionAnalysisEvent.php | 79 ++ .../Psalm/Storage/ClassConstantStorage.php | 35 + .../src/Psalm/Storage/ClassLikeStorage.php | 54 +- .../src/Psalm/Storage/FunctionLikeStorage.php | 78 +- vendor/vimeo/psalm/src/Psalm/Type.php | 26 +- .../src/Psalm/Type/Atomic/CallableTrait.php | 21 +- .../Type/Atomic/HasIntersectionTrait.php | 14 +- .../psalm/src/Psalm/Type/Atomic/TArray.php | 2 +- .../psalm/src/Psalm/Type/Atomic/TCallable.php | 21 + .../src/Psalm/Type/Atomic/TCallableObject.php | 17 +- .../src/Psalm/Type/Atomic/TClassConstant.php | 2 +- .../src/Psalm/Type/Atomic/TClassString.php | 2 +- .../src/Psalm/Type/Atomic/TClassStringMap.php | 2 +- .../psalm/src/Psalm/Type/Atomic/TClosure.php | 12 +- .../src/Psalm/Type/Atomic/TConditional.php | 2 +- .../Psalm/Type/Atomic/TDependentGetClass.php | 1 + .../Type/Atomic/TDependentGetDebugType.php | 1 + .../Psalm/Type/Atomic/TDependentGetType.php | 1 + .../Psalm/Type/Atomic/TDependentListKey.php | 1 + .../src/Psalm/Type/Atomic/TGenericObject.php | 13 +- .../psalm/src/Psalm/Type/Atomic/TIntMask.php | 2 +- .../src/Psalm/Type/Atomic/TIntMaskOf.php | 2 +- .../psalm/src/Psalm/Type/Atomic/TIntRange.php | 2 +- .../psalm/src/Psalm/Type/Atomic/TIterable.php | 4 +- .../psalm/src/Psalm/Type/Atomic/TKeyOf.php | 2 +- .../src/Psalm/Type/Atomic/TKeyedArray.php | 88 +- .../psalm/src/Psalm/Type/Atomic/TList.php | 2 +- .../src/Psalm/Type/Atomic/TLiteralFloat.php | 2 +- .../src/Psalm/Type/Atomic/TLiteralInt.php | 2 +- .../src/Psalm/Type/Atomic/TLiteralString.php | 2 +- .../psalm/src/Psalm/Type/Atomic/TMixed.php | 2 +- .../src/Psalm/Type/Atomic/TNamedObject.php | 4 +- .../src/Psalm/Type/Atomic/TNonEmptyArray.php | 3 +- .../src/Psalm/Type/Atomic/TNonEmptyList.php | 4 +- .../Type/Atomic/TObjectWithProperties.php | 7 +- .../src/Psalm/Type/Atomic/TPropertiesOf.php | 2 +- .../src/Psalm/Type/Atomic/TSingleLetter.php | 2 +- .../Type/Atomic/TTemplateIndexedAccess.php | 2 +- .../src/Psalm/Type/Atomic/TTemplateKeyOf.php | 2 +- .../src/Psalm/Type/Atomic/TTemplateParam.php | 2 +- .../Psalm/Type/Atomic/TTemplateParamClass.php | 11 +- .../Type/Atomic/TTemplatePropertiesOf.php | 2 +- .../Psalm/Type/Atomic/TTemplateValueOf.php | 2 +- .../src/Psalm/Type/Atomic/TTypeAlias.php | 10 + .../Psalm/Type/Atomic/TUnknownClassString.php | 30 + .../psalm/src/Psalm/Type/Atomic/TValueOf.php | 41 +- .../vimeo/psalm/src/Psalm/Type/Reconciler.php | 2 +- .../vimeo/psalm/src/Psalm/Type/UnionTrait.php | 37 +- .../psalm/stubs/CoreGenericClasses.phpstub | 90 ++ .../psalm/stubs/CoreGenericFunctions.phpstub | 80 +- .../psalm/stubs/CoreGenericIterators.phpstub | 2 +- vendor/vimeo/psalm/stubs/Php82.phpstub | 9 + .../psalm/stubs/extensions/mysqli.phpstub | 51 ++ .../psalm/stubs/extensions/simplexml.phpstub | 1 + www/composer.json | 3 +- www/composer.lock | 121 ++- www/vendor/composer/autoload_classmap.php | 4 + www/vendor/composer/autoload_psr4.php | 1 + www/vendor/composer/autoload_static.php | 9 + www/vendor/composer/installed.json | 132 ++- www/vendor/composer/installed.php | 39 +- www/vendor/myclabs/deep-copy/README.md | 35 +- .../deep-copy/src/DeepCopy/DeepCopy.php | 5 + .../src/DeepCopy/Filter/ChainableFilter.php | 24 + www/vendor/nikic/php-parser/grammar/php7.y | 6 +- .../lib/PhpParser/Builder/Param.php | 48 +- .../php-parser/lib/PhpParser/Parser/Php7.php | 4 +- .../lib/PhpParser/ParserAbstract.php | 21 + .../{ChangeLog.md => ChangeLog-9.2.md} | 7 + .../phpunit/php-code-coverage/composer.json | 4 +- .../src/Report/Html/Renderer/File.php | 2 +- .../Html/Renderer/Template/css/style.css | 28 + .../ExecutableLinesFindingVisitor.php | 9 +- .../phpunit/php-code-coverage/src/Version.php | 2 +- www/vendor/phpunit/phpunit/ChangeLog-8.5.md | 304 ------- www/vendor/phpunit/phpunit/ChangeLog-9.6.md | 32 + www/vendor/phpunit/phpunit/composer.json | 7 +- www/vendor/phpunit/phpunit/phpunit | 21 +- .../phpunit/phpunit/src/Framework/Assert.php | 4 +- .../Constraint/Equality/IsEqualWithDelta.php | 2 +- .../src/Framework/MockObject/Generator.php | 3 - .../phpunit/src/Framework/TestResult.php | 1 + .../phpunit/phpunit/src/Runner/Version.php | 2 +- .../src/TextUI/CliArguments/Builder.php | 1 - .../phpunit/phpunit/src/TextUI/Command.php | 25 +- .../src/TextUI/DefaultResultPrinter.php | 24 +- .../phpunit/phpunit/src/TextUI/Help.php | 3 +- .../phpunit/phpunit/src/TextUI/TestRunner.php | 6 +- .../phpunit/src/Util/Annotation/DocBlock.php | 15 +- .../phpunit/phpunit/src/Util/GlobalState.php | 84 ++ www/vendor/phpunit/phpunit/src/Util/Test.php | 2 +- .../src/Util/TestDox/CliTestDoxPrinter.php | 1 - .../src/Util/TestDox/HtmlResultPrinter.php | 45 +- www/vendor/psr/log/LICENSE | 19 + www/vendor/psr/log/README.md | 58 ++ www/vendor/psr/log/composer.json | 26 + www/vendor/psr/log/src/AbstractLogger.php | 15 + .../psr/log/src/InvalidArgumentException.php | 7 + www/vendor/psr/log/src/LogLevel.php | 18 + .../psr/log/src/LoggerAwareInterface.php | 18 + www/vendor/psr/log/src/LoggerAwareTrait.php | 26 + www/vendor/psr/log/src/LoggerInterface.php | 125 +++ www/vendor/psr/log/src/LoggerTrait.php | 142 +++ www/vendor/psr/log/src/NullLogger.php | 30 + www/vendor/sebastian/diff/ChangeLog.md | 8 + ...ientLongestCommonSubsequenceCalculator.php | 7 +- ...ientLongestCommonSubsequenceCalculator.php | 24 +- 304 files changed, 11398 insertions(+), 3199 deletions(-) create mode 100644 vendor/netresearch/jsonmapper/.github/workflows/test.yml create mode 100644 vendor/phpstan/phpdoc-parser/phpstan-baseline.neon create mode 100644 vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Ast/Attribute.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Printer/Differ.php create mode 100644 vendor/phpstan/phpdoc-parser/src/Printer/Printer.php create mode 100644 vendor/vimeo/psalm/docs/running_psalm/issues/InheritorViolation.md create mode 100644 vendor/vimeo/psalm/docs/running_psalm/issues/UnsupportedPropertyReferenceUsage.md create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgHandler.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgInfo.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/Codebase/StorageByPatternResolver.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Workspace.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ClientConfiguration.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/PHPMarkdownContent.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Progress.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ClassLikeStorageCacheProvider.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ParserCacheProvider.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ProjectCacheProvider.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Reference.php delete mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayUniqueReturnTypeProvider.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/DateReturnTypeProvider.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/PowReturnTypeProvider.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumNameFetch.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumPropertyFetch.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumValueFetch.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Issue/InheritorViolation.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Issue/UnsupportedPropertyReferenceUsage.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Plugin/EventHandler/BeforeExpressionAnalysisInterface.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Plugin/EventHandler/Event/BeforeExpressionAnalysisEvent.php create mode 100644 vendor/vimeo/psalm/src/Psalm/Type/Atomic/TUnknownClassString.php create mode 100644 www/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ChainableFilter.php rename www/vendor/phpunit/php-code-coverage/{ChangeLog.md => ChangeLog-9.2.md} (99%) delete mode 100644 www/vendor/phpunit/phpunit/ChangeLog-8.5.md create mode 100644 www/vendor/psr/log/LICENSE create mode 100644 www/vendor/psr/log/README.md create mode 100644 www/vendor/psr/log/composer.json create mode 100644 www/vendor/psr/log/src/AbstractLogger.php create mode 100644 www/vendor/psr/log/src/InvalidArgumentException.php create mode 100644 www/vendor/psr/log/src/LogLevel.php create mode 100644 www/vendor/psr/log/src/LoggerAwareInterface.php create mode 100644 www/vendor/psr/log/src/LoggerAwareTrait.php create mode 100644 www/vendor/psr/log/src/LoggerInterface.php create mode 100644 www/vendor/psr/log/src/LoggerTrait.php create mode 100644 www/vendor/psr/log/src/NullLogger.php diff --git a/composer.json b/composer.json index d34abf3b..b18cd23f 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,7 @@ } }, "require": { - "php": ">=8.1" + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" } } diff --git a/composer.lock b/composer.lock index 7c17f09f..5d70e659 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,59 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c633a27ea30371ec870c8065ca4ae4cd", - "packages": [], + "content-hash": "9a62d2bdd387b7a6f599b27964325845", + "packages": [ + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + } + ], "packages-dev": [ { "name": "amphp/amp", @@ -680,16 +731,16 @@ }, { "name": "netresearch/jsonmapper", - "version": "v4.1.0", + "version": "v4.2.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f" + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", "shasum": "" }, "require": { @@ -725,22 +776,22 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" }, - "time": "2022-12-08T20:46:14+00:00" + "time": "2023-04-09T17:37:40+00:00" }, { "name": "nikic/php-parser", - "version": "v4.15.4", + "version": "v4.15.5", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "shasum": "" }, "require": { @@ -781,9 +832,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" }, - "time": "2023-03-05T19:49:14+00:00" + "time": "2023-05-19T20:20:00+00:00" }, { "name": "phan/phan", @@ -1034,22 +1085,22 @@ }, { "name": "phpstan/extension-installer", - "version": "1.2.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/phpstan/extension-installer.git", - "reference": "f06dbb052ddc394e7896fcd1cfcd533f9f6ace40" + "reference": "f45734bfb9984c6c56c4486b71230355f066a58a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/f06dbb052ddc394e7896fcd1cfcd533f9f6ace40", - "reference": "f06dbb052ddc394e7896fcd1cfcd533f9f6ace40", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/f45734bfb9984c6c56c4486b71230355f066a58a", + "reference": "f45734bfb9984c6c56c4486b71230355f066a58a", "shasum": "" }, "require": { "composer-plugin-api": "^2.0", "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.8.0" + "phpstan/phpstan": "^1.9.0" }, "require-dev": { "composer/composer": "^2.0", @@ -1072,28 +1123,29 @@ "description": "Composer plugin for automatic installation of PHPStan extensions", "support": { "issues": "https://github.com/phpstan/extension-installer/issues", - "source": "https://github.com/phpstan/extension-installer/tree/1.2.0" + "source": "https://github.com/phpstan/extension-installer/tree/1.3.1" }, - "time": "2022-10-17T12:59:16+00:00" + "time": "2023-05-24T08:59:17+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.16.1", + "version": "1.21.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571" + "reference": "6df62b08faef4f899772bc7c3bbabb93d2b7a21c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e27e92d939e2e3636f0a1f0afaba59692c0bf571", - "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6df62b08faef4f899772bc7c3bbabb93d2b7a21c", + "reference": "6df62b08faef4f899772bc7c3bbabb93d2b7a21c", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { + "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.5", @@ -1117,22 +1169,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.16.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.21.0" }, - "time": "2023-02-07T18:11:17+00:00" + "time": "2023-05-17T13:13:44+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.8", + "version": "1.10.15", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0166aef76e066f0dd2adc2799bdadfa1635711e9" + "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0166aef76e066f0dd2adc2799bdadfa1635711e9", - "reference": "0166aef76e066f0dd2adc2799bdadfa1635711e9", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd", + "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd", "shasum": "" }, "require": { @@ -1181,7 +1233,7 @@ "type": "tidelift" } ], - "time": "2023-03-24T10:28:16+00:00" + "time": "2023-05-09T15:28:01+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -1284,56 +1336,6 @@ }, "time": "2021-11-05T16:47:00+00:00" }, - { - "name": "psr/log", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" - }, - "time": "2021-07-14T16:46:02+00:00" - }, { "name": "sabre/event", "version": "5.1.4", @@ -1402,16 +1404,16 @@ }, { "name": "sebastian/diff", - "version": "5.0.1", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "aae9a0a43bff37bd5d8d0311426c87bf36153f02" + "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/aae9a0a43bff37bd5d8d0311426c87bf36153f02", - "reference": "aae9a0a43bff37bd5d8d0311426c87bf36153f02", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/912dc2fbe3e3c1e7873313cc801b100b6c68c87b", + "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b", "shasum": "" }, "require": { @@ -1457,7 +1459,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/diff/tree/5.0.3" }, "funding": [ { @@ -1465,20 +1467,20 @@ "type": "github" } ], - "time": "2023-03-23T05:12:41+00:00" + "time": "2023-05-01T07:48:21+00:00" }, { "name": "spatie/array-to-xml", - "version": "3.1.5", + "version": "3.1.6", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "13f76acef5362d15c71ae1ac6350cc3df5e25e43" + "reference": "e210b98957987c755372465be105d32113f339a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/13f76acef5362d15c71ae1ac6350cc3df5e25e43", - "reference": "13f76acef5362d15c71ae1ac6350cc3df5e25e43", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/e210b98957987c755372465be105d32113f339a4", + "reference": "e210b98957987c755372465be105d32113f339a4", "shasum": "" }, "require": { @@ -1516,7 +1518,7 @@ "xml" ], "support": { - "source": "https://github.com/spatie/array-to-xml/tree/3.1.5" + "source": "https://github.com/spatie/array-to-xml/tree/3.1.6" }, "funding": [ { @@ -1528,20 +1530,20 @@ "type": "github" } ], - "time": "2022-12-24T13:43:51+00:00" + "time": "2023-05-11T14:04:07+00:00" }, { "name": "symfony/console", - "version": "v6.2.7", + "version": "v6.2.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cbad09eb8925b6ad4fb721c7a179344dc4a19d45" + "reference": "5aa03db8ef0a5457c316ec580e69562d97734c77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cbad09eb8925b6ad4fb721c7a179344dc4a19d45", - "reference": "cbad09eb8925b6ad4fb721c7a179344dc4a19d45", + "url": "https://api.github.com/repos/symfony/console/zipball/5aa03db8ef0a5457c316ec580e69562d97734c77", + "reference": "5aa03db8ef0a5457c316ec580e69562d97734c77", "shasum": "" }, "require": { @@ -1603,12 +1605,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.2.7" + "source": "https://github.com/symfony/console/tree/v6.2.11" }, "funding": [ { @@ -1624,7 +1626,7 @@ "type": "tidelift" } ], - "time": "2023-02-25T17:00:03+00:00" + "time": "2023-05-26T08:16:21+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1695,16 +1697,16 @@ }, { "name": "symfony/filesystem", - "version": "v6.2.7", + "version": "v6.2.10", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "82b6c62b959f642d000456f08c6d219d749215b3" + "reference": "fd588debf7d1bc16a2c84b4b3b71145d9946b894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/82b6c62b959f642d000456f08c6d219d749215b3", - "reference": "82b6c62b959f642d000456f08c6d219d749215b3", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/fd588debf7d1bc16a2c84b4b3b71145d9946b894", + "reference": "fd588debf7d1bc16a2c84b4b3b71145d9946b894", "shasum": "" }, "require": { @@ -1738,7 +1740,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.2.7" + "source": "https://github.com/symfony/filesystem/tree/v6.2.10" }, "funding": [ { @@ -1754,7 +1756,7 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:44:56+00:00" + "time": "2023-04-18T13:46:08+00:00" }, { "name": "symfony/polyfill-ctype", @@ -2256,16 +2258,16 @@ }, { "name": "symfony/string", - "version": "v6.2.7", + "version": "v6.2.8", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "67b8c1eec78296b85dc1c7d9743830160218993d" + "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/67b8c1eec78296b85dc1c7d9743830160218993d", - "reference": "67b8c1eec78296b85dc1c7d9743830160218993d", + "url": "https://api.github.com/repos/symfony/string/zipball/193e83bbd6617d6b2151c37fff10fa7168ebddef", + "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef", "shasum": "" }, "require": { @@ -2322,7 +2324,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.2.7" + "source": "https://github.com/symfony/string/tree/v6.2.8" }, "funding": [ { @@ -2338,7 +2340,7 @@ "type": "tidelift" } ], - "time": "2023-02-24T10:42:00+00:00" + "time": "2023-03-20T16:06:02+00:00" }, { "name": "tysonandre/var_representation_polyfill", @@ -2404,16 +2406,16 @@ }, { "name": "vimeo/psalm", - "version": "5.8.0", + "version": "5.12.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "9cf4f60a333f779ad3bc704a555920e81d4fdcda" + "reference": "f90118cdeacd0088e7215e64c0c99ceca819e176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/9cf4f60a333f779ad3bc704a555920e81d4fdcda", - "reference": "9cf4f60a333f779ad3bc704a555920e81d4fdcda", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/f90118cdeacd0088e7215e64c0c99ceca819e176", + "reference": "f90118cdeacd0088e7215e64c0c99ceca819e176", "shasum": "" }, "require": { @@ -2445,6 +2447,7 @@ "psalm/psalm": "self.version" }, "require-dev": { + "amphp/phpunit-util": "^2.0", "bamarni/composer-bin-plugin": "^1.4", "brianium/paratest": "^6.9", "ext-curl": "*", @@ -2503,9 +2506,9 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/5.8.0" + "source": "https://github.com/vimeo/psalm/tree/5.12.0" }, - "time": "2023-03-09T04:14:35+00:00" + "time": "2023-05-22T21:19:03+00:00" }, { "name": "webmozart/assert", diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 2fe33c4b..b453d2e1 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -706,17 +706,17 @@ }, { "name": "netresearch/jsonmapper", - "version": "v4.1.0", - "version_normalized": "4.1.0.0", + "version": "v4.2.0", + "version_normalized": "4.2.0.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f" + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", "shasum": "" }, "require": { @@ -730,7 +730,7 @@ "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", "squizlabs/php_codesniffer": "~3.5" }, - "time": "2022-12-08T20:46:14+00:00", + "time": "2023-04-09T17:37:40+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -754,23 +754,23 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" }, "install-path": "../netresearch/jsonmapper" }, { "name": "nikic/php-parser", - "version": "v4.15.4", - "version_normalized": "4.15.4.0", + "version": "v4.15.5", + "version_normalized": "4.15.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "shasum": "" }, "require": { @@ -781,7 +781,7 @@ "ircmaxell/php-yacc": "^0.0.7", "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, - "time": "2023-03-05T19:49:14+00:00", + "time": "2023-05-19T20:20:00+00:00", "bin": [ "bin/php-parse" ], @@ -813,7 +813,7 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" }, "install-path": "../nikic/php-parser" }, @@ -1078,30 +1078,30 @@ }, { "name": "phpstan/extension-installer", - "version": "1.2.0", - "version_normalized": "1.2.0.0", + "version": "1.3.1", + "version_normalized": "1.3.1.0", "source": { "type": "git", "url": "https://github.com/phpstan/extension-installer.git", - "reference": "f06dbb052ddc394e7896fcd1cfcd533f9f6ace40" + "reference": "f45734bfb9984c6c56c4486b71230355f066a58a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/f06dbb052ddc394e7896fcd1cfcd533f9f6ace40", - "reference": "f06dbb052ddc394e7896fcd1cfcd533f9f6ace40", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/f45734bfb9984c6c56c4486b71230355f066a58a", + "reference": "f45734bfb9984c6c56c4486b71230355f066a58a", "shasum": "" }, "require": { "composer-plugin-api": "^2.0", "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.8.0" + "phpstan/phpstan": "^1.9.0" }, "require-dev": { "composer/composer": "^2.0", "php-parallel-lint/php-parallel-lint": "^1.2.0", "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" }, - "time": "2022-10-17T12:59:16+00:00", + "time": "2023-05-24T08:59:17+00:00", "type": "composer-plugin", "extra": { "class": "PHPStan\\ExtensionInstaller\\Plugin" @@ -1119,29 +1119,30 @@ "description": "Composer plugin for automatic installation of PHPStan extensions", "support": { "issues": "https://github.com/phpstan/extension-installer/issues", - "source": "https://github.com/phpstan/extension-installer/tree/1.2.0" + "source": "https://github.com/phpstan/extension-installer/tree/1.3.1" }, "install-path": "../phpstan/extension-installer" }, { "name": "phpstan/phpdoc-parser", - "version": "1.16.1", - "version_normalized": "1.16.1.0", + "version": "1.21.0", + "version_normalized": "1.21.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571" + "reference": "6df62b08faef4f899772bc7c3bbabb93d2b7a21c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e27e92d939e2e3636f0a1f0afaba59692c0bf571", - "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6df62b08faef4f899772bc7c3bbabb93d2b7a21c", + "reference": "6df62b08faef4f899772bc7c3bbabb93d2b7a21c", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { + "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.5", @@ -1150,7 +1151,7 @@ "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" }, - "time": "2023-02-07T18:11:17+00:00", + "time": "2023-05-17T13:13:44+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1167,23 +1168,23 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.16.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.21.0" }, "install-path": "../phpstan/phpdoc-parser" }, { "name": "phpstan/phpstan", - "version": "1.10.8", - "version_normalized": "1.10.8.0", + "version": "1.10.15", + "version_normalized": "1.10.15.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0166aef76e066f0dd2adc2799bdadfa1635711e9" + "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0166aef76e066f0dd2adc2799bdadfa1635711e9", - "reference": "0166aef76e066f0dd2adc2799bdadfa1635711e9", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd", + "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd", "shasum": "" }, "require": { @@ -1192,7 +1193,7 @@ "conflict": { "phpstan/phpstan-shim": "*" }, - "time": "2023-03-24T10:28:16+00:00", + "time": "2023-05-09T15:28:01+00:00", "bin": [ "phpstan", "phpstan.phar" @@ -1467,17 +1468,17 @@ }, { "name": "sebastian/diff", - "version": "5.0.1", - "version_normalized": "5.0.1.0", + "version": "5.0.3", + "version_normalized": "5.0.3.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "aae9a0a43bff37bd5d8d0311426c87bf36153f02" + "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/aae9a0a43bff37bd5d8d0311426c87bf36153f02", - "reference": "aae9a0a43bff37bd5d8d0311426c87bf36153f02", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/912dc2fbe3e3c1e7873313cc801b100b6c68c87b", + "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b", "shasum": "" }, "require": { @@ -1487,7 +1488,7 @@ "phpunit/phpunit": "^10.0", "symfony/process": "^4.2 || ^5" }, - "time": "2023-03-23T05:12:41+00:00", + "time": "2023-05-01T07:48:21+00:00", "type": "library", "extra": { "branch-alias": { @@ -1525,7 +1526,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/diff/tree/5.0.3" }, "funding": [ { @@ -1537,17 +1538,17 @@ }, { "name": "spatie/array-to-xml", - "version": "3.1.5", - "version_normalized": "3.1.5.0", + "version": "3.1.6", + "version_normalized": "3.1.6.0", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "13f76acef5362d15c71ae1ac6350cc3df5e25e43" + "reference": "e210b98957987c755372465be105d32113f339a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/13f76acef5362d15c71ae1ac6350cc3df5e25e43", - "reference": "13f76acef5362d15c71ae1ac6350cc3df5e25e43", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/e210b98957987c755372465be105d32113f339a4", + "reference": "e210b98957987c755372465be105d32113f339a4", "shasum": "" }, "require": { @@ -1559,7 +1560,7 @@ "pestphp/pest": "^1.21", "spatie/pest-plugin-snapshots": "^1.1" }, - "time": "2022-12-24T13:43:51+00:00", + "time": "2023-05-11T14:04:07+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1587,7 +1588,7 @@ "xml" ], "support": { - "source": "https://github.com/spatie/array-to-xml/tree/3.1.5" + "source": "https://github.com/spatie/array-to-xml/tree/3.1.6" }, "funding": [ { @@ -1603,17 +1604,17 @@ }, { "name": "symfony/console", - "version": "v6.2.7", - "version_normalized": "6.2.7.0", + "version": "v6.2.11", + "version_normalized": "6.2.11.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cbad09eb8925b6ad4fb721c7a179344dc4a19d45" + "reference": "5aa03db8ef0a5457c316ec580e69562d97734c77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cbad09eb8925b6ad4fb721c7a179344dc4a19d45", - "reference": "cbad09eb8925b6ad4fb721c7a179344dc4a19d45", + "url": "https://api.github.com/repos/symfony/console/zipball/5aa03db8ef0a5457c316ec580e69562d97734c77", + "reference": "5aa03db8ef0a5457c316ec580e69562d97734c77", "shasum": "" }, "require": { @@ -1648,7 +1649,7 @@ "symfony/lock": "", "symfony/process": "" }, - "time": "2023-02-25T17:00:03+00:00", + "time": "2023-05-26T08:16:21+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1677,12 +1678,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.2.7" + "source": "https://github.com/symfony/console/tree/v6.2.11" }, "funding": [ { @@ -1772,17 +1773,17 @@ }, { "name": "symfony/filesystem", - "version": "v6.2.7", - "version_normalized": "6.2.7.0", + "version": "v6.2.10", + "version_normalized": "6.2.10.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "82b6c62b959f642d000456f08c6d219d749215b3" + "reference": "fd588debf7d1bc16a2c84b4b3b71145d9946b894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/82b6c62b959f642d000456f08c6d219d749215b3", - "reference": "82b6c62b959f642d000456f08c6d219d749215b3", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/fd588debf7d1bc16a2c84b4b3b71145d9946b894", + "reference": "fd588debf7d1bc16a2c84b4b3b71145d9946b894", "shasum": "" }, "require": { @@ -1790,7 +1791,7 @@ "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, - "time": "2023-02-14T08:44:56+00:00", + "time": "2023-04-18T13:46:08+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1818,7 +1819,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.2.7" + "source": "https://github.com/symfony/filesystem/tree/v6.2.10" }, "funding": [ { @@ -2354,17 +2355,17 @@ }, { "name": "symfony/string", - "version": "v6.2.7", - "version_normalized": "6.2.7.0", + "version": "v6.2.8", + "version_normalized": "6.2.8.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "67b8c1eec78296b85dc1c7d9743830160218993d" + "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/67b8c1eec78296b85dc1c7d9743830160218993d", - "reference": "67b8c1eec78296b85dc1c7d9743830160218993d", + "url": "https://api.github.com/repos/symfony/string/zipball/193e83bbd6617d6b2151c37fff10fa7168ebddef", + "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef", "shasum": "" }, "require": { @@ -2384,7 +2385,7 @@ "symfony/translation-contracts": "^2.0|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, - "time": "2023-02-24T10:42:00+00:00", + "time": "2023-03-20T16:06:02+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2423,7 +2424,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.2.7" + "source": "https://github.com/symfony/string/tree/v6.2.8" }, "funding": [ { @@ -2508,17 +2509,17 @@ }, { "name": "vimeo/psalm", - "version": "5.8.0", - "version_normalized": "5.8.0.0", + "version": "5.12.0", + "version_normalized": "5.12.0.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "9cf4f60a333f779ad3bc704a555920e81d4fdcda" + "reference": "f90118cdeacd0088e7215e64c0c99ceca819e176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/9cf4f60a333f779ad3bc704a555920e81d4fdcda", - "reference": "9cf4f60a333f779ad3bc704a555920e81d4fdcda", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/f90118cdeacd0088e7215e64c0c99ceca819e176", + "reference": "f90118cdeacd0088e7215e64c0c99ceca819e176", "shasum": "" }, "require": { @@ -2550,6 +2551,7 @@ "psalm/psalm": "self.version" }, "require-dev": { + "amphp/phpunit-util": "^2.0", "bamarni/composer-bin-plugin": "^1.4", "brianium/paratest": "^6.9", "ext-curl": "*", @@ -2568,7 +2570,7 @@ "ext-curl": "In order to send data to shepherd", "ext-igbinary": "^2.0.5 is required, used to serialize caching data" }, - "time": "2023-03-09T04:14:35+00:00", + "time": "2023-05-22T21:19:03+00:00", "bin": [ "psalm", "psalm-language-server", @@ -2610,7 +2612,7 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/5.8.0" + "source": "https://github.com/vimeo/psalm/tree/5.12.0" }, "install-path": "../vimeo/psalm" }, @@ -2700,7 +2702,6 @@ "phpstan/phpstan", "phpstan/phpstan-deprecation-rules", "psr/container", - "psr/log", "sabre/event", "sebastian/diff", "spatie/array-to-xml", diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 9f147870..2059fa41 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -119,18 +119,18 @@ 'dev_requirement' => true, ), 'netresearch/jsonmapper' => array( - 'pretty_version' => 'v4.1.0', - 'version' => '4.1.0.0', - 'reference' => 'cfa81ea1d35294d64adb9c68aa4cb9e92400e53f', + 'pretty_version' => 'v4.2.0', + 'version' => '4.2.0.0', + 'reference' => 'f60565f8c0566a31acf06884cdaa591867ecc956', 'type' => 'library', 'install_path' => __DIR__ . '/../netresearch/jsonmapper', 'aliases' => array(), 'dev_requirement' => true, ), 'nikic/php-parser' => array( - 'pretty_version' => 'v4.15.4', - 'version' => '4.15.4.0', - 'reference' => '6bb5176bc4af8bcb7d926f88718db9b96a2d4290', + 'pretty_version' => 'v4.15.5', + 'version' => '4.15.5.0', + 'reference' => '11e2663a5bc9db5d714eedb4277ee300403b4a9e', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), @@ -173,27 +173,27 @@ 'dev_requirement' => true, ), 'phpstan/extension-installer' => array( - 'pretty_version' => '1.2.0', - 'version' => '1.2.0.0', - 'reference' => 'f06dbb052ddc394e7896fcd1cfcd533f9f6ace40', + 'pretty_version' => '1.3.1', + 'version' => '1.3.1.0', + 'reference' => 'f45734bfb9984c6c56c4486b71230355f066a58a', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/../phpstan/extension-installer', 'aliases' => array(), 'dev_requirement' => true, ), 'phpstan/phpdoc-parser' => array( - 'pretty_version' => '1.16.1', - 'version' => '1.16.1.0', - 'reference' => 'e27e92d939e2e3636f0a1f0afaba59692c0bf571', + 'pretty_version' => '1.21.0', + 'version' => '1.21.0.0', + 'reference' => '6df62b08faef4f899772bc7c3bbabb93d2b7a21c', 'type' => 'library', 'install_path' => __DIR__ . '/../phpstan/phpdoc-parser', 'aliases' => array(), 'dev_requirement' => true, ), 'phpstan/phpstan' => array( - 'pretty_version' => '1.10.8', - 'version' => '1.10.8.0', - 'reference' => '0166aef76e066f0dd2adc2799bdadfa1635711e9', + 'pretty_version' => '1.10.15', + 'version' => '1.10.15.0', + 'reference' => '762c4dac4da6f8756eebb80e528c3a47855da9bd', 'type' => 'library', 'install_path' => __DIR__ . '/../phpstan/phpstan', 'aliases' => array(), @@ -211,7 +211,7 @@ 'psalm/psalm' => array( 'dev_requirement' => true, 'provided' => array( - 0 => '5.8.0', + 0 => '5.12.0', ), ), 'psr/container' => array( @@ -230,7 +230,7 @@ 'type' => 'library', 'install_path' => __DIR__ . '/../psr/log', 'aliases' => array(), - 'dev_requirement' => true, + 'dev_requirement' => false, ), 'psr/log-implementation' => array( 'dev_requirement' => true, @@ -248,27 +248,27 @@ 'dev_requirement' => true, ), 'sebastian/diff' => array( - 'pretty_version' => '5.0.1', - 'version' => '5.0.1.0', - 'reference' => 'aae9a0a43bff37bd5d8d0311426c87bf36153f02', + 'pretty_version' => '5.0.3', + 'version' => '5.0.3.0', + 'reference' => '912dc2fbe3e3c1e7873313cc801b100b6c68c87b', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/diff', 'aliases' => array(), 'dev_requirement' => true, ), 'spatie/array-to-xml' => array( - 'pretty_version' => '3.1.5', - 'version' => '3.1.5.0', - 'reference' => '13f76acef5362d15c71ae1ac6350cc3df5e25e43', + 'pretty_version' => '3.1.6', + 'version' => '3.1.6.0', + 'reference' => 'e210b98957987c755372465be105d32113f339a4', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/array-to-xml', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/console' => array( - 'pretty_version' => 'v6.2.7', - 'version' => '6.2.7.0', - 'reference' => 'cbad09eb8925b6ad4fb721c7a179344dc4a19d45', + 'pretty_version' => 'v6.2.11', + 'version' => '6.2.11.0', + 'reference' => '5aa03db8ef0a5457c316ec580e69562d97734c77', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), @@ -284,9 +284,9 @@ 'dev_requirement' => true, ), 'symfony/filesystem' => array( - 'pretty_version' => 'v6.2.7', - 'version' => '6.2.7.0', - 'reference' => '82b6c62b959f642d000456f08c6d219d749215b3', + 'pretty_version' => 'v6.2.10', + 'version' => '6.2.10.0', + 'reference' => 'fd588debf7d1bc16a2c84b4b3b71145d9946b894', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/filesystem', 'aliases' => array(), @@ -347,9 +347,9 @@ 'dev_requirement' => true, ), 'symfony/string' => array( - 'pretty_version' => 'v6.2.7', - 'version' => '6.2.7.0', - 'reference' => '67b8c1eec78296b85dc1c7d9743830160218993d', + 'pretty_version' => 'v6.2.8', + 'version' => '6.2.8.0', + 'reference' => '193e83bbd6617d6b2151c37fff10fa7168ebddef', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/string', 'aliases' => array(), @@ -365,9 +365,9 @@ 'dev_requirement' => true, ), 'vimeo/psalm' => array( - 'pretty_version' => '5.8.0', - 'version' => '5.8.0.0', - 'reference' => '9cf4f60a333f779ad3bc704a555920e81d4fdcda', + 'pretty_version' => '5.12.0', + 'version' => '5.12.0.0', + 'reference' => 'f90118cdeacd0088e7215e64c0c99ceca819e176', 'type' => 'library', 'install_path' => __DIR__ . '/../vimeo/psalm', 'aliases' => array(), diff --git a/vendor/netresearch/jsonmapper/.github/workflows/test.yml b/vendor/netresearch/jsonmapper/.github/workflows/test.yml new file mode 100644 index 00000000..76a8d654 --- /dev/null +++ b/vendor/netresearch/jsonmapper/.github/workflows/test.yml @@ -0,0 +1,46 @@ +name: JsonMapper tests +on: [push, workflow_dispatch] +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + php-versions: + - '7.1' + - '7.2' + - '7.3' + - '7.4' + - '8.0' + - '8.1' + - '8.2' + name: PHP ${{ matrix.php-versions }} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + tools: composer + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ matrix.php-versions }}-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer-${{ matrix.php-versions }}- + + - name: Install dependencies + run: composer install --no-interaction --prefer-dist + + - name: Run unit tests + run: XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-text + + - name: Check codestyle + run: ./vendor/bin/phpcs --standard=PEAR src/ diff --git a/vendor/netresearch/jsonmapper/src/JsonMapper.php b/vendor/netresearch/jsonmapper/src/JsonMapper.php index fdb984f0..5ae3895b 100644 --- a/vendor/netresearch/jsonmapper/src/JsonMapper.php +++ b/vendor/netresearch/jsonmapper/src/JsonMapper.php @@ -75,7 +75,7 @@ class JsonMapper public $bStrictNullTypes = true; /** - * Allow mapping of private and proteted properties. + * Allow mapping of private and protected properties. * * @var boolean */ @@ -131,8 +131,8 @@ class JsonMapper /** * Map data all data in $json into the given $object instance. * - * @param object|array $json JSON object structure from json_decode() - * @param object $object Object to map $json data into + * @param object|array $json JSON object structure from json_decode() + * @param object|class-string $object Object to map $json data into * * @return mixed Mapped object is returned. * @see mapArray() @@ -145,13 +145,18 @@ class JsonMapper . ', ' . gettype($json) . ' given.' ); } - if (!is_object($object)) { + if (!is_object($object) && (!is_string($object) || !class_exists($object))) { throw new InvalidArgumentException( - 'JsonMapper::map() requires second argument to be an object' + 'JsonMapper::map() requires second argument to ' + . 'be an object or existing class name' . ', ' . gettype($object) . ' given.' ); } + if (is_string($object)) { + $object = $this->createInstance($object); + } + $strClassName = get_class($object); $rc = new ReflectionClass($object); $strNs = $rc->getNamespaceName(); @@ -177,10 +182,15 @@ class JsonMapper . ' in object of type ' . $strClassName ); } else if ($this->undefinedPropertyHandler !== null) { - call_user_func( + $undefinedPropertyKey = call_user_func( $this->undefinedPropertyHandler, $object, $key, $jvalue ); + + if (is_string($undefinedPropertyKey)) { + list($hasProperty, $accessor, $type, $isNullable) + = $this->inspectProperty($rc, $undefinedPropertyKey); + } } else { $this->log( 'info', @@ -188,7 +198,10 @@ class JsonMapper array('property' => $key, 'class' => $strClassName) ); } - continue; + + if (!$hasProperty) { + continue; + } } if ($accessor === null) { @@ -229,7 +242,9 @@ class JsonMapper } else if ($this->isObjectOfSameType($type, $jvalue)) { $this->setProperty($object, $accessor, $jvalue); continue; - } else if ($this->isSimpleType($type)) { + } else if ($this->isSimpleType($type) + && !(is_array($jvalue) && $this->hasVariadicArrayType($accessor)) + ) { if ($type === 'string' && is_object($jvalue)) { throw new JsonMapper_Exception( 'JSON property "' . $key . '" in class "' @@ -268,8 +283,11 @@ class JsonMapper } else { $array = $this->createInstance($proptype, false, $jvalue); } + } else if (is_array($jvalue) && $this->hasVariadicArrayType($accessor)) { + $array = array(); + $subtype = $type; } else { - if (is_a($type, 'ArrayObject', true)) { + if (is_a($type, 'ArrayAccess', true)) { $array = $this->createInstance($type, false, $jvalue); } } @@ -625,6 +643,8 @@ class JsonMapper } if ($accessor instanceof ReflectionProperty) { $accessor->setValue($object, $value); + } else if (is_array($value) && $this->hasVariadicArrayType($accessor)) { + $accessor->invoke($object, ...$value); } else { //setter method $accessor->invoke($object, $value); @@ -647,6 +667,12 @@ class JsonMapper $class, $useParameter = false, $jvalue = null ) { if ($useParameter) { + if (PHP_VERSION_ID >= 80100 + && is_subclass_of($class, \BackedEnum::class) + ) { + return $class::from($jvalue); + } + return new $class($jvalue); } else { $reflectClass = new ReflectionClass($class); @@ -758,6 +784,32 @@ class JsonMapper return substr($strType, -2) === '[]'; } + /** + * Returns true if accessor is a method and has only one parameter + * which is variadic. + * + * @param ReflectionMethod|ReflectionProperty|null $accessor accessor + * to set value + * + * @return bool + */ + protected function hasVariadicArrayType($accessor) + { + if (!$accessor instanceof ReflectionMethod) { + return false; + } + + $parameters = $accessor->getParameters(); + + if (count($parameters) !== 1) { + return false; + } + + $parameter = $parameters[0]; + + return $parameter->isVariadic(); + } + /** * Checks if the given type is nullable * diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php index de9aae7e..69f35332 100644 --- a/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php @@ -19,6 +19,8 @@ class Param implements PhpParser\Builder protected $variadic = false; + protected $flags = 0; + /** @var Node\AttributeGroup[] */ protected $attributeGroups = []; @@ -95,6 +97,50 @@ class Param implements PhpParser\Builder return $this; } + /** + * Makes the (promoted) parameter public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PUBLIC); + + return $this; + } + + /** + * Makes the (promoted) parameter protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PROTECTED); + + return $this; + } + + /** + * Makes the (promoted) parameter private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PRIVATE); + + return $this; + } + + /** + * Makes the (promoted) parameter readonly. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeReadonly() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_READONLY); + + return $this; + } + /** * Adds an attribute group. * @@ -116,7 +162,7 @@ class Param implements PhpParser\Builder public function getNode() : Node { return new Node\Param( new Node\Expr\Variable($this->name), - $this->default, $this->type, $this->byRef, $this->variadic, [], 0, $this->attributeGroups + $this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups ); } } diff --git a/vendor/phpstan/extension-installer/README.md b/vendor/phpstan/extension-installer/README.md index 70afa415..0616f999 100644 --- a/vendor/phpstan/extension-installer/README.md +++ b/vendor/phpstan/extension-installer/README.md @@ -72,6 +72,22 @@ Add `phpstan` key in the extension `composer.json`'s `extra` section: } ``` +## Ignoring a particular extension + +You may want to disable auto-installation of a particular extension to handle installation manually. Ignore an extension by adding an `extra.phpstan/extension-installer.ignore` array in `composer.json` that specifies a list of packages to ignore: + +```json +{ + "extra": { + "phpstan/extension-installer": { + "ignore": [ + "phpstan/phpstan-phpunit" + ] + } + } +} +``` + ## Limitations The extension installer depends on Composer script events, therefore you cannot use `--no-scripts` flag. diff --git a/vendor/phpstan/extension-installer/build-cs/composer.json b/vendor/phpstan/extension-installer/build-cs/composer.json index e3079710..16a240bc 100644 --- a/vendor/phpstan/extension-installer/build-cs/composer.json +++ b/vendor/phpstan/extension-installer/build-cs/composer.json @@ -1,8 +1,9 @@ { "require-dev": { - "consistence-community/coding-standard": "^3.10", - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", - "slevomat/coding-standard": "^7.0" + "consistence-community/coding-standard": "^3.11.0", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0", + "slevomat/coding-standard": "^8.8.0", + "squizlabs/php_codesniffer": "^3.5.3" }, "config": { "allow-plugins": { diff --git a/vendor/phpstan/extension-installer/build-cs/composer.lock b/vendor/phpstan/extension-installer/build-cs/composer.lock index 4bcc8de4..db122416 100644 --- a/vendor/phpstan/extension-installer/build-cs/composer.lock +++ b/vendor/phpstan/extension-installer/build-cs/composer.lock @@ -4,35 +4,35 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4485bbedba7bcc71ace5f69dbb9b6c47", + "content-hash": "e69c1916405a7e3c8001c1b609a0ee61", "packages": [], "packages-dev": [ { "name": "consistence-community/coding-standard", - "version": "3.11.1", + "version": "3.11.3", "source": { "type": "git", "url": "https://github.com/consistence-community/coding-standard.git", - "reference": "4632fead8c9ee8f50044fcbce9f66c797b34c0df" + "reference": "f38e06327d5bf80ff5ff523a2c05e623b5e8d8b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consistence-community/coding-standard/zipball/4632fead8c9ee8f50044fcbce9f66c797b34c0df", - "reference": "4632fead8c9ee8f50044fcbce9f66c797b34c0df", + "url": "https://api.github.com/repos/consistence-community/coding-standard/zipball/f38e06327d5bf80ff5ff523a2c05e623b5e8d8b1", + "reference": "f38e06327d5bf80ff5ff523a2c05e623b5e8d8b1", "shasum": "" }, "require": { - "php": ">=7.4", - "slevomat/coding-standard": "~7.0", - "squizlabs/php_codesniffer": "~3.6.0" + "php": "~8.0", + "slevomat/coding-standard": "~8.0", + "squizlabs/php_codesniffer": "~3.7.0" }, "replace": { "consistence/coding-standard": "3.10.*" }, "require-dev": { - "phing/phing": "2.16.4", - "php-parallel-lint/php-parallel-lint": "1.3.0", - "phpunit/phpunit": "9.5.4" + "phing/phing": "2.17.0", + "php-parallel-lint/php-parallel-lint": "1.3.1", + "phpunit/phpunit": "9.5.10" }, "type": "library", "autoload": { @@ -70,41 +70,44 @@ ], "support": { "issues": "https://github.com/consistence-community/coding-standard/issues", - "source": "https://github.com/consistence-community/coding-standard/tree/3.11.1" + "source": "https://github.com/consistence-community/coding-standard/tree/3.11.3" }, - "time": "2021-05-03T18:13:22+00:00" + "time": "2023-03-27T14:55:41+00:00" }, { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.7.2", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db" + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", - "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", "shasum": "" }, "require": { "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3", + "php": ">=5.4", "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, "require-dev": { "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", "php-parallel-lint/php-parallel-lint": "^1.3.1", - "phpcompatibility/php-compatibility": "^9.0" + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" }, "type": "composer-plugin", "extra": { - "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" }, "autoload": { "psr-4": { - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -120,7 +123,7 @@ }, { "name": "Contributors", - "homepage": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors" + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", @@ -144,23 +147,23 @@ "tests" ], "support": { - "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", - "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" }, - "time": "2022-02-04T12:51:07+00:00" + "time": "2023-01-05T11:28:13+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.5.1", + "version": "1.20.4", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "981cc368a216c988e862a75e526b6076987d1b50" + "reference": "7d568c87a9df9c5f7e8b5f075fc469aa8cb0a4cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/981cc368a216c988e862a75e526b6076987d1b50", - "reference": "981cc368a216c988e862a75e526b6076987d1b50", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/7d568c87a9df9c5f7e8b5f075fc469aa8cb0a4cd", + "reference": "7d568c87a9df9c5f7e8b5f075fc469aa8cb0a4cd", "shasum": "" }, "require": { @@ -170,6 +173,7 @@ "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" @@ -189,48 +193,48 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.5.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.20.4" }, - "time": "2022-05-05T11:32:40+00:00" + "time": "2023-05-02T09:19:37+00:00" }, { "name": "slevomat/coding-standard", - "version": "7.2.1", + "version": "8.12.0", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "aff06ae7a84e4534bf6f821dc982a93a5d477c90" + "reference": "cc04334ed0ce5a251389112fbd2dbe1dbc931ae8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/aff06ae7a84e4534bf6f821dc982a93a5d477c90", - "reference": "aff06ae7a84e4534bf6f821dc982a93a5d477c90", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/cc04334ed0ce5a251389112fbd2dbe1dbc931ae8", + "reference": "cc04334ed0ce5a251389112fbd2dbe1dbc931ae8", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", "php": "^7.2 || ^8.0", - "phpstan/phpdoc-parser": "^1.5.1", - "squizlabs/php_codesniffer": "^3.6.2" + "phpstan/phpdoc-parser": ">=1.20.0 <1.21.0", + "squizlabs/php_codesniffer": "^3.7.1" }, "require-dev": { - "phing/phing": "2.17.3", + "phing/phing": "2.17.4", "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "1.4.10|1.7.1", - "phpstan/phpstan-deprecation-rules": "1.0.0", - "phpstan/phpstan-phpunit": "1.0.0|1.1.1", - "phpstan/phpstan-strict-rules": "1.2.3", - "phpunit/phpunit": "7.5.20|8.5.21|9.5.20" + "phpstan/phpstan": "1.10.15", + "phpstan/phpstan-deprecation-rules": "1.1.3", + "phpstan/phpstan-phpunit": "1.3.11", + "phpstan/phpstan-strict-rules": "1.5.1", + "phpunit/phpunit": "7.5.20|8.5.21|9.6.8|10.1.3" }, "type": "phpcodesniffer-standard", "extra": { "branch-alias": { - "dev-master": "7.x-dev" + "dev-master": "8.x-dev" } }, "autoload": { "psr-4": { - "SlevomatCodingStandard\\": "SlevomatCodingStandard" + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" } }, "notification-url": "https://packagist.org/downloads/", @@ -238,9 +242,13 @@ "MIT" ], "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/7.2.1" + "source": "https://github.com/slevomat/coding-standard/tree/8.12.0" }, "funding": [ { @@ -252,20 +260,20 @@ "type": "tidelift" } ], - "time": "2022-05-25T10:58:12+00:00" + "time": "2023-05-14T20:06:01+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.6.2", + "version": "3.7.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a" + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", "shasum": "" }, "require": { @@ -301,14 +309,15 @@ "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "keywords": [ "phpcs", - "standards" + "standards", + "static analysis" ], "support": { "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2021-12-12T21:44:58+00:00" + "time": "2023-02-22T23:07:41+00:00" } ], "aliases": [], diff --git a/vendor/phpstan/extension-installer/composer.json b/vendor/phpstan/extension-installer/composer.json index c57fcfe5..f2865a39 100644 --- a/vendor/phpstan/extension-installer/composer.json +++ b/vendor/phpstan/extension-installer/composer.json @@ -8,7 +8,7 @@ "require": { "php": "^7.2 || ^8.0", "composer-plugin-api": "^2.0", - "phpstan/phpstan": "^1.8.0" + "phpstan/phpstan": "^1.9.0" }, "require-dev": { "composer/composer": "^2.0", diff --git a/vendor/phpstan/extension-installer/src/GeneratedConfig.php b/vendor/phpstan/extension-installer/src/GeneratedConfig.php index 3c9004ac..a5a02fad 100644 --- a/vendor/phpstan/extension-installer/src/GeneratedConfig.php +++ b/vendor/phpstan/extension-installer/src/GeneratedConfig.php @@ -3,21 +3,30 @@ namespace PHPStan\ExtensionInstaller; /** - * This is a stub class: it is in place only for scenarios where Composer - * is run with a `--no-scripts` flag, in which scenarios this stub class - * is not being replaced. - * - * If you are reading this docBlock inside your `vendor/` dir, then this means - * that phpstan/extension-installer didn't correctly install. - * + * This class is generated by phpstan/extension-installer. * @internal */ final class GeneratedConfig { - public const EXTENSIONS = []; + public const EXTENSIONS = array ( + 'phpstan/phpstan-deprecation-rules' => + array ( + 'install_path' => '/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/vendor/phpstan/phpstan-deprecation-rules', + 'relative_install_path' => '../../phpstan-deprecation-rules', + 'extra' => + array ( + 'includes' => + array ( + 0 => 'rules.neon', + ), + ), + 'version' => '1.1.3', + ), +); - public const NOT_INSTALLED = []; + public const NOT_INSTALLED = array ( +); private function __construct() { diff --git a/vendor/phpstan/extension-installer/src/Plugin.php b/vendor/phpstan/extension-installer/src/Plugin.php index 4ff82e4b..b8e605bd 100644 --- a/vendor/phpstan/extension-installer/src/Plugin.php +++ b/vendor/phpstan/extension-installer/src/Plugin.php @@ -19,6 +19,7 @@ use function is_file; use function ksort; use function md5; use function md5_file; +use function sort; use function sprintf; use function strpos; use function var_export; @@ -97,9 +98,18 @@ PHP; } $notInstalledPackages = []; $installedPackages = []; + $ignoredPackages = []; $data = []; $fs = new Filesystem(); + $ignore = []; + + $packageExtra = $composer->getPackage()->getExtra(); + + if (isset($packageExtra['phpstan/extension-installer']['ignore'])) { + $ignore = $packageExtra['phpstan/extension-installer']['ignore']; + } + foreach ($composer->getRepositoryManager()->getLocalRepository()->getPackages() as $package) { if ( $package->getType() !== 'phpstan-extension' @@ -119,7 +129,15 @@ PHP; continue; } + if (in_array($package->getName(), $ignore, true)) { + $ignoredPackages[] = $package->getName(); + continue; + } + $installPath = $installationManager->getInstallPath($package); + if ($installPath === null) { + continue; + } $absoluteInstallPath = $fs->isAbsolutePath($installPath) ? $installPath @@ -138,6 +156,7 @@ PHP; ksort($data); ksort($installedPackages); ksort($notInstalledPackages); + sort($ignoredPackages); $generatedConfigFileContents = sprintf(self::$generatedFileTemplate, var_export($data, true), var_export($notInstalledPackages, true)); file_put_contents($generatedConfigFilePath, $generatedConfigFileContents); @@ -154,6 +173,10 @@ PHP; foreach (array_keys($notInstalledPackages) as $name) { $io->write(sprintf('> %s: not supported', $name)); } + + foreach ($ignoredPackages as $name) { + $io->write(sprintf('> %s: ignored', $name)); + } } } diff --git a/vendor/phpstan/phpdoc-parser/README.md b/vendor/phpstan/phpdoc-parser/README.md index 080e25ee..2d2f6c82 100644 --- a/vendor/phpstan/phpdoc-parser/README.md +++ b/vendor/phpstan/phpdoc-parser/README.md @@ -1,4 +1,4 @@ -

PHPDoc-Parser for PHPStan

+

PHPDoc Parser for PHPStan

Build Status @@ -7,11 +7,99 @@ PHPStan Enabled

-* [PHPStan](https://phpstan.org) +This library `phpstan/phpdoc-parser` represents PHPDocs with an AST (Abstract Syntax Tree). It supports parsing and modifying PHPDocs. ------- +For the complete list of supported PHPDoc features check out PHPStan documentation. PHPStan is the main (but not the only) user of this library. -Next generation phpDoc parser with support for intersection types and generics. +* [PHPDoc Basics](https://phpstan.org/writing-php-code/phpdocs-basics) (list of PHPDoc tags) +* [PHPDoc Types](https://phpstan.org/writing-php-code/phpdoc-types) (list of PHPDoc types) +* [phpdoc-parser API Reference](https://phpstan.github.io/phpdoc-parser/namespace-PHPStan.PhpDocParser.html) with all the AST node types etc. + +## Installation + +``` +composer require phpstan/phpdoc-parser +``` + +## Basic usage + +```php +tokenize('/** @param Lorem $a */')); +$phpDocNode = $phpDocParser->parse($tokens); // PhpDocNode +$paramTags = $phpDocNode->getParamTagValues(); // ParamTagValueNode[] +echo $paramTags[0]->parameterName; // '$a' +echo $paramTags[0]->type; // IdentifierTypeNode - 'Lorem' +``` + +### Format-preserving printer + +This component can be used to modify the AST +and print it again as close as possible to the original. + +It's heavily inspired by format-preserving printer component in [nikic/PHP-Parser](https://github.com/nikic/PHP-Parser). + +```php + true, 'indexes' => true]; + +$lexer = new Lexer(); +$constExprParser = new ConstExprParser(true, true, $usedAttributes); +$typeParser = new TypeParser($constExprParser, true, $usedAttributes); +$phpDocParser = new PhpDocParser($typeParser, $constExprParser, true, true, $usedAttributes); + +$tokens = new TokenIterator($lexer->tokenize('/** @param Lorem $a */')); +$phpDocNode = $phpDocParser->parse($tokens); // PhpDocNode + +$cloningTraverser = new NodeTraverser([new CloningVisitor()]); + +/** @var PhpDocNode $newPhpDocNode */ +$printer = new Printer(); +[$newPhpDocNode] = $cloningTraverser->traverse([$phpDocNode]); + +// change something in $newPhpDocNode +$newPhpDocNode->getParamTagValues()[0]->type = new IdentifierTypeNode('Ipsum'); + +$newPhpDoc = $printer->printFormatPreserving($newPhpDocNode, $phpDocNode, $tokens); +echo $newPhpDoc; // '/** @param Ipsum $a */' +``` ## Code of Conduct diff --git a/vendor/phpstan/phpdoc-parser/composer.json b/vendor/phpstan/phpdoc-parser/composer.json index 3b902ae2..30b879b7 100644 --- a/vendor/phpstan/phpdoc-parser/composer.json +++ b/vendor/phpstan/phpdoc-parser/composer.json @@ -6,6 +6,7 @@ "php": "^7.2 || ^8.0" }, "require-dev": { + "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.5", diff --git a/vendor/phpstan/phpdoc-parser/phpstan-baseline.neon b/vendor/phpstan/phpdoc-parser/phpstan-baseline.neon new file mode 100644 index 00000000..04100fcd --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/phpstan-baseline.neon @@ -0,0 +1,31 @@ +parameters: + ignoreErrors: + - + message: "#^Method PHPStan\\\\PhpDocParser\\\\Ast\\\\ConstExpr\\\\QuoteAwareConstExprStringNode\\:\\:escapeDoubleQuotedString\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php + + - + message: "#^Cannot use array destructuring on array\\\\|int\\|string\\>\\|null\\.$#" + count: 1 + path: src/Ast/NodeTraverser.php + + - + message: "#^Strict comparison using \\=\\=\\= between 2 and 2 will always evaluate to true\\.$#" + count: 2 + path: src/Ast/NodeTraverser.php + + - + message: "#^Variable property access on PHPStan\\\\PhpDocParser\\\\Ast\\\\Node\\.$#" + count: 1 + path: src/Ast/NodeTraverser.php + + - + message: "#^Method PHPStan\\\\PhpDocParser\\\\Parser\\\\StringUnescaper\\:\\:parseEscapeSequences\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/Parser/StringUnescaper.php + + - + message: "#^Variable property access on PHPStan\\\\PhpDocParser\\\\Ast\\\\Node\\.$#" + count: 2 + path: src/Printer/Printer.php diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php b/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php new file mode 100644 index 00000000..32d1a04a --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php @@ -0,0 +1,34 @@ +quoteType = $quoteType; + } + + + public function __toString(): string + { + if ($this->quoteType === self::SINGLE_QUOTED) { + // from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1007 + return sprintf("'%s'", addcslashes($this->value, '\'\\')); + } + + // from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1010-L1040 + return sprintf('"%s"', $this->escapeDoubleQuotedString()); + } + + private function escapeDoubleQuotedString(): string + { + $quote = '"'; + $escaped = addcslashes($this->value, "\n\r\t\f\v$" . $quote . '\\'); + + // Escape control characters and non-UTF-8 characters. + // Regex based on https://stackoverflow.com/a/11709412/385378. + $regex = '/( + [\x00-\x08\x0E-\x1F] # Control characters + | [\xC0-\xC1] # Invalid UTF-8 Bytes + | [\xF5-\xFF] # Invalid UTF-8 Bytes + | \xE0(?=[\x80-\x9F]) # Overlong encoding of prior code point + | \xF0(?=[\x80-\x8F]) # Overlong encoding of prior code point + | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start + | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start + | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start + | (?<=[\x00-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle + | (? Visitors */ + private $visitors = []; + + /** @var bool Whether traversal should be stopped */ + private $stopTraversal; + + /** + * @param list $visitors + */ + public function __construct(array $visitors) + { + $this->visitors = $visitors; + } + + /** + * Traverses an array of nodes using the registered visitors. + * + * @param Node[] $nodes Array of nodes + * + * @return Node[] Traversed array of nodes + */ + public function traverse(array $nodes): array + { + $this->stopTraversal = false; + + foreach ($this->visitors as $visitor) { + $return = $visitor->beforeTraverse($nodes); + if ($return === null) { + continue; + } + + $nodes = $return; + } + + $nodes = $this->traverseArray($nodes); + + foreach ($this->visitors as $visitor) { + $return = $visitor->afterTraverse($nodes); + if ($return === null) { + continue; + } + + $nodes = $return; + } + + return $nodes; + } + + /** + * Recursively traverse a node. + * + * @param Node $node Node to traverse. + * + * @return Node Result of traversal (may be original node or new one) + */ + private function traverseNode(Node $node): Node + { + $subNodeNames = array_keys(get_object_vars($node)); + foreach ($subNodeNames as $name) { + $subNode =& $node->$name; + + if (is_array($subNode)) { + $subNode = $this->traverseArray($subNode); + if ($this->stopTraversal) { + break; + } + } elseif ($subNode instanceof Node) { + $traverseChildren = true; + $breakVisitorIndex = null; + + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->enterNode($subNode); + if ($return === null) { + continue; + } + + if ($return instanceof Node) { + $this->ensureReplacementReasonable($subNode, $return); + $subNode = $return; + } elseif ($return === self::DONT_TRAVERSE_CHILDREN) { + $traverseChildren = false; + } elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) { + $traverseChildren = false; + $breakVisitorIndex = $visitorIndex; + break; + } elseif ($return === self::STOP_TRAVERSAL) { + $this->stopTraversal = true; + break 2; + } else { + throw new LogicException( + 'enterNode() returned invalid value of type ' . gettype($return) + ); + } + } + + if ($traverseChildren) { + $subNode = $this->traverseNode($subNode); + if ($this->stopTraversal) { + break; + } + } + + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->leaveNode($subNode); + + if ($return !== null) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($subNode, $return); + $subNode = $return; + } elseif ($return === self::STOP_TRAVERSAL) { + $this->stopTraversal = true; + break 2; + } elseif (is_array($return)) { + throw new LogicException( + 'leaveNode() may only return an array ' . + 'if the parent structure is an array' + ); + } else { + throw new LogicException( + 'leaveNode() returned invalid value of type ' . gettype($return) + ); + } + } + + if ($breakVisitorIndex === $visitorIndex) { + break; + } + } + } + } + + return $node; + } + + /** + * Recursively traverse array (usually of nodes). + * + * @param mixed[] $nodes Array to traverse + * + * @return mixed[] Result of traversal (may be original array or changed one) + */ + private function traverseArray(array $nodes): array + { + $doNodes = []; + + foreach ($nodes as $i => &$node) { + if ($node instanceof Node) { + $traverseChildren = true; + $breakVisitorIndex = null; + + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->enterNode($node); + if ($return === null) { + continue; + } + + if ($return instanceof Node) { + $this->ensureReplacementReasonable($node, $return); + $node = $return; + } elseif (is_array($return)) { + $doNodes[] = [$i, $return]; + continue 2; + } elseif ($return === self::REMOVE_NODE) { + $doNodes[] = [$i, []]; + continue 2; + } elseif ($return === self::DONT_TRAVERSE_CHILDREN) { + $traverseChildren = false; + } elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) { + $traverseChildren = false; + $breakVisitorIndex = $visitorIndex; + break; + } elseif ($return === self::STOP_TRAVERSAL) { + $this->stopTraversal = true; + break 2; + } else { + throw new LogicException( + 'enterNode() returned invalid value of type ' . gettype($return) + ); + } + } + + if ($traverseChildren) { + $node = $this->traverseNode($node); + if ($this->stopTraversal) { + break; + } + } + + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->leaveNode($node); + + if ($return !== null) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($node, $return); + $node = $return; + } elseif (is_array($return)) { + $doNodes[] = [$i, $return]; + break; + } elseif ($return === self::REMOVE_NODE) { + $doNodes[] = [$i, []]; + break; + } elseif ($return === self::STOP_TRAVERSAL) { + $this->stopTraversal = true; + break 2; + } else { + throw new LogicException( + 'leaveNode() returned invalid value of type ' . gettype($return) + ); + } + } + + if ($breakVisitorIndex === $visitorIndex) { + break; + } + } + } elseif (is_array($node)) { + throw new LogicException('Invalid node structure: Contains nested arrays'); + } + } + + if (count($doNodes) > 0) { + while ([$i, $replace] = array_pop($doNodes)) { + array_splice($nodes, $i, 1, $replace); + } + } + + return $nodes; + } + + private function ensureReplacementReasonable(Node $old, Node $new): void + { + if ($old instanceof TypeNode && !$new instanceof TypeNode) { + throw new LogicException(sprintf('Trying to replace TypeNode with %s', get_class($new))); + } + + if ($old instanceof ConstExprNode && !$new instanceof ConstExprNode) { + throw new LogicException(sprintf('Trying to replace ConstExprNode with %s', get_class($new))); + } + + if ($old instanceof PhpDocChildNode && !$new instanceof PhpDocChildNode) { + throw new LogicException(sprintf('Trying to replace PhpDocChildNode with %s', get_class($new))); + } + + if ($old instanceof PhpDocTagValueNode && !$new instanceof PhpDocTagValueNode) { + throw new LogicException(sprintf('Trying to replace PhpDocTagValueNode with %s', get_class($new))); + } + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php b/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php new file mode 100644 index 00000000..bf7d784e --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php @@ -0,0 +1,87 @@ + $node stays as-is + * * array (of Nodes) + * => The return value is merged into the parent array (at the position of the $node) + * * NodeTraverser::REMOVE_NODE + * => $node is removed from the parent array + * * NodeTraverser::DONT_TRAVERSE_CHILDREN + * => Children of $node are not traversed. $node stays as-is + * * NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN + * => Further visitors for the current node are skipped, and its children are not + * traversed. $node stays as-is. + * * NodeTraverser::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * otherwise + * => $node is set to the return value + * + * @param Node $node Node + * + * @return Node|Node[]|NodeTraverser::*|null Replacement node (or special return value) + */ + public function enterNode(Node $node); + + /** + * Called when leaving a node. + * + * Return value semantics: + * * null + * => $node stays as-is + * * NodeTraverser::REMOVE_NODE + * => $node is removed from the parent array + * * NodeTraverser::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * array (of Nodes) + * => The return value is merged into the parent array (at the position of the $node) + * * otherwise + * => $node is set to the return value + * + * @param Node $node Node + * + * @return Node|Node[]|NodeTraverser::REMOVE_NODE|NodeTraverser::STOP_TRAVERSAL|null Replacement node (or special return value) + */ + public function leaveNode(Node $node); + + /** + * Called once after traversal. + * + * Return value semantics: + * * null: $nodes stays as-is + * * otherwise: $nodes is set to the return value + * + * @param Node[] $nodes Array of nodes + * + * @return Node[]|null Array of nodes + */ + public function afterTraverse(array $nodes): ?array; + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php b/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php new file mode 100644 index 00000000..7200f3af --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php @@ -0,0 +1,20 @@ +setAttribute(Attribute::ORIGINAL_NODE, $originalNode); + + return $node; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php index 17bf04f2..ca7b4f20 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php @@ -31,10 +31,11 @@ class InvalidTagValueNode implements PhpDocTagValueNode $exception->getCurrentOffset(), $exception->getExpectedTokenType(), $exception->getExpectedTokenValue(), + $exception->getCurrentTokenLine(), ]; } - public function __get(string $name) + public function __get(string $name): ?ParserException { if ($name !== 'exception') { trigger_error(sprintf('Undefined property: %s::$%s', self::class, $name), E_USER_WARNING); diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php index 075cec04..211510be 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php @@ -30,6 +30,10 @@ class MethodTagValueNode implements PhpDocTagValueNode /** @var string (may be empty) */ public $description; + /** + * @param MethodTagValueParameterNode[] $parameters + * @param TemplateTagValueNode[] $templateTypes + */ public function __construct(bool $isStatic, ?TypeNode $returnType, string $methodName, array $parameters, string $description, array $templateTypes = []) { $this->isStatic = $isStatic; diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php index 41941f80..806783f9 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php @@ -23,6 +23,7 @@ class ArrayShapeNode implements TypeNode public $kind; /** + * @param ArrayShapeItemNode[] $items * @param self::KIND_* $kind */ public function __construct(array $items, bool $sealed = true, string $kind = self::KIND_ARRAY) diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php index 90cb9f08..d2031032 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php @@ -20,6 +20,14 @@ class ArrayTypeNode implements TypeNode public function __toString(): string { + if ( + $this->type instanceof CallableTypeNode + || $this->type instanceof ConstTypeNode + || $this->type instanceof NullableTypeNode + ) { + return '(' . $this->type . ')[]'; + } + return $this->type . '[]'; } diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php index 83ade94c..e57e5f82 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php @@ -19,6 +19,9 @@ class CallableTypeNode implements TypeNode /** @var TypeNode */ public $returnType; + /** + * @param CallableTypeParameterNode[] $parameters + */ public function __construct(IdentifierTypeNode $identifier, array $parameters, TypeNode $returnType) { $this->identifier = $identifier; @@ -29,8 +32,12 @@ class CallableTypeNode implements TypeNode public function __toString(): string { + $returnType = $this->returnType; + if ($returnType instanceof self) { + $returnType = "({$returnType})"; + } $parameters = implode(', ', $this->parameters); - return "{$this->identifier}({$parameters}): {$this->returnType}"; + return "{$this->identifier}({$parameters}): {$returnType}"; } } diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php index 7ab2d7e3..c78d4c7b 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php @@ -41,8 +41,8 @@ class CallableTypeParameterNode implements Node $type = "{$this->type} "; $isReference = $this->isReference ? '&' : ''; $isVariadic = $this->isVariadic ? '...' : ''; - $default = $this->isOptional ? ' = default' : ''; - return trim("{$type}{$isReference}{$isVariadic}{$this->parameterName}") . $default; + $isOptional = $this->isOptional ? '=' : ''; + return trim("{$type}{$isReference}{$isVariadic}{$this->parameterName}") . $isOptional; } } diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php index 179de55a..44e1d16d 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php @@ -25,6 +25,10 @@ class GenericTypeNode implements TypeNode /** @var (self::VARIANCE_*)[] */ public $variances; + /** + * @param TypeNode[] $genericTypes + * @param (self::VARIANCE_*)[] $variances + */ public function __construct(IdentifierTypeNode $type, array $genericTypes, array $variances = []) { $this->type = $type; diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php index 7f9aff33..fd761cf7 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php @@ -3,6 +3,7 @@ namespace PHPStan\PhpDocParser\Ast\Type; use PHPStan\PhpDocParser\Ast\NodeAttributes; +use function array_map; use function implode; class IntersectionTypeNode implements TypeNode @@ -13,6 +14,9 @@ class IntersectionTypeNode implements TypeNode /** @var TypeNode[] */ public $types; + /** + * @param TypeNode[] $types + */ public function __construct(array $types) { $this->types = $types; @@ -21,7 +25,13 @@ class IntersectionTypeNode implements TypeNode public function __toString(): string { - return '(' . implode(' & ', $this->types) . ')'; + return '(' . implode(' & ', array_map(static function (TypeNode $type): string { + if ($type instanceof NullableTypeNode) { + return '(' . $type . ')'; + } + + return (string) $type; + }, $this->types)) . ')'; } } diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php new file mode 100644 index 00000000..1ec47cf6 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php @@ -0,0 +1,38 @@ +exceptionArgs = [ + $exception->getCurrentTokenValue(), + $exception->getCurrentTokenType(), + $exception->getCurrentOffset(), + $exception->getExpectedTokenType(), + $exception->getExpectedTokenValue(), + $exception->getCurrentTokenLine(), + ]; + } + + public function getException(): ParserException + { + return new ParserException(...$this->exceptionArgs); + } + + public function __toString(): string + { + return '*Invalid type*'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php new file mode 100644 index 00000000..2f012406 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php @@ -0,0 +1,48 @@ +keyName = $keyName; + $this->optional = $optional; + $this->valueType = $valueType; + } + + + public function __toString(): string + { + if ($this->keyName !== null) { + return sprintf( + '%s%s: %s', + (string) $this->keyName, + $this->optional ? '?' : '', + (string) $this->valueType + ); + } + + return (string) $this->valueType; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php new file mode 100644 index 00000000..f418bc30 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php @@ -0,0 +1,31 @@ +items = $items; + } + + public function __toString(): string + { + $items = $this->items; + + return 'object{' . implode(', ', $items) . '}'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php index 1d5b04ef..39e83dfe 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php @@ -23,6 +23,14 @@ class OffsetAccessTypeNode implements TypeNode public function __toString(): string { + if ( + $this->type instanceof CallableTypeNode + || $this->type instanceof ConstTypeNode + || $this->type instanceof NullableTypeNode + ) { + return '(' . $this->type . ')[' . $this->offset . ']'; + } + return $this->type . '[' . $this->offset . ']'; } diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php index 08acf56c..c552dab5 100644 --- a/vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php @@ -3,6 +3,7 @@ namespace PHPStan\PhpDocParser\Ast\Type; use PHPStan\PhpDocParser\Ast\NodeAttributes; +use function array_map; use function implode; class UnionTypeNode implements TypeNode @@ -13,6 +14,9 @@ class UnionTypeNode implements TypeNode /** @var TypeNode[] */ public $types; + /** + * @param TypeNode[] $types + */ public function __construct(array $types) { $this->types = $types; @@ -21,7 +25,13 @@ class UnionTypeNode implements TypeNode public function __toString(): string { - return '(' . implode(' | ', $this->types) . ')'; + return '(' . implode(' | ', array_map(static function (TypeNode $type): string { + if ($type instanceof NullableTypeNode) { + return '(' . $type . ')'; + } + + return (string) $type; + }, $this->types)) . ')'; } } diff --git a/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php b/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php index 1b98839d..ccae6bef 100644 --- a/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php +++ b/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php @@ -88,10 +88,14 @@ class Lexer public const VALUE_OFFSET = 0; public const TYPE_OFFSET = 1; + public const LINE_OFFSET = 2; /** @var string|null */ private $regexp; + /** + * @return list + */ public function tokenize(string $s): array { if ($this->regexp === null) { @@ -101,11 +105,18 @@ class Lexer preg_match_all($this->regexp, $s, $matches, PREG_SET_ORDER); $tokens = []; + $line = 1; foreach ($matches as $match) { - $tokens[] = [$match[0], (int) $match['MARK']]; + $type = (int) $match['MARK']; + $tokens[] = [$match[0], $type, $line]; + if ($type !== self::TOKEN_PHPDOC_EOL) { + continue; + } + + $line++; } - $tokens[] = ['', self::TOKEN_END]; + $tokens[] = ['', self::TOKEN_END, $line]; return $tokens; } @@ -149,8 +160,8 @@ class Lexer self::TOKEN_PHPDOC_TAG => '@(?:[a-z][a-z0-9-\\\\]+:)?[a-z][a-z0-9-\\\\]*+', self::TOKEN_PHPDOC_EOL => '\\r?+\\n[\\x09\\x20]*+(?:\\*(?!/)\\x20?+)?', - self::TOKEN_FLOAT => '(?:-?[0-9]++\\.[0-9]*+(?:e-?[0-9]++)?)|(?:-?[0-9]*+\\.[0-9]++(?:e-?[0-9]++)?)|(?:-?[0-9]++e-?[0-9]++)', - self::TOKEN_INTEGER => '-?(?:(?:0b[0-1]++)|(?:0o[0-7]++)|(?:0x[0-9a-f]++)|(?:[0-9]++))', + self::TOKEN_FLOAT => '(?:-?[0-9]++(_[0-9]++)*\\.[0-9]*(_[0-9]++)*+(?:e-?[0-9]++(_[0-9]++)*)?)|(?:-?[0-9]*+(_[0-9]++)*\\.[0-9]++(_[0-9]++)*(?:e-?[0-9]++(_[0-9]++)*)?)|(?:-?[0-9]++(_[0-9]++)*e-?[0-9]++(_[0-9]++)*)', + self::TOKEN_INTEGER => '-?(?:(?:0b[0-1]++(_[0-1]++)*)|(?:0o[0-7]++(_[0-7]++)*)|(?:0x[0-9a-f]++(_[0-9a-f]++)*)|(?:[0-9]++(_[0-9]++)*))', self::TOKEN_SINGLE_QUOTED_STRING => '\'(?:\\\\[^\\r\\n]|[^\'\\r\\n\\\\])*+\'', self::TOKEN_DOUBLE_QUOTED_STRING => '"(?:\\\\[^\\r\\n]|[^"\\r\\n\\\\])*+"', diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php b/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php index d7876303..b6db8a2c 100644 --- a/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php +++ b/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php @@ -4,10 +4,6 @@ namespace PHPStan\PhpDocParser\Parser; use PHPStan\PhpDocParser\Ast; use PHPStan\PhpDocParser\Lexer\Lexer; -use function chr; -use function hexdec; -use function octdec; -use function preg_replace_callback; use function str_replace; use function strtolower; use function substr; @@ -15,49 +11,93 @@ use function substr; class ConstExprParser { - private const REPLACEMENTS = [ - '\\' => '\\', - 'n' => "\n", - 'r' => "\r", - 't' => "\t", - 'f' => "\f", - 'v' => "\v", - 'e' => "\x1B", - ]; - /** @var bool */ private $unescapeStrings; - public function __construct(bool $unescapeStrings = false) + /** @var bool */ + private $quoteAwareConstExprString; + + /** @var bool */ + private $useLinesAttributes; + + /** @var bool */ + private $useIndexAttributes; + + /** + * @param array{lines?: bool, indexes?: bool} $usedAttributes + */ + public function __construct( + bool $unescapeStrings = false, + bool $quoteAwareConstExprString = false, + array $usedAttributes = [] + ) { $this->unescapeStrings = $unescapeStrings; + $this->quoteAwareConstExprString = $quoteAwareConstExprString; + $this->useLinesAttributes = $usedAttributes['lines'] ?? false; + $this->useIndexAttributes = $usedAttributes['indexes'] ?? false; } public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\ConstExpr\ConstExprNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_FLOAT)) { $value = $tokens->currentTokenValue(); $tokens->next(); - return new Ast\ConstExpr\ConstExprFloatNode($value); + + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprFloatNode(str_replace('_', '', $value)), + $startLine, + $startIndex + ); } if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) { $value = $tokens->currentTokenValue(); $tokens->next(); - return new Ast\ConstExpr\ConstExprIntegerNode($value); + + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $value)), + $startLine, + $startIndex + ); } if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING, Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { $value = $tokens->currentTokenValue(); + $type = $tokens->currentTokenType(); if ($trimStrings) { if ($this->unescapeStrings) { - $value = self::unescapeString($value); + $value = StringUnescaper::unescapeString($value); } else { $value = substr($value, 1, -1); } } $tokens->next(); - return new Ast\ConstExpr\ConstExprStringNode($value); + + if ($this->quoteAwareConstExprString) { + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\QuoteAwareConstExprStringNode( + $value, + $type === Lexer::TOKEN_SINGLE_QUOTED_STRING + ? Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED + : Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED + ), + $startLine, + $startIndex + ); + } + + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprStringNode($value), + $startLine, + $startIndex + ); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { $identifier = $tokens->currentTokenValue(); @@ -65,14 +105,29 @@ class ConstExprParser switch (strtolower($identifier)) { case 'true': - return new Ast\ConstExpr\ConstExprTrueNode(); + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprTrueNode(), + $startLine, + $startIndex + ); case 'false': - return new Ast\ConstExpr\ConstExprFalseNode(); + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprFalseNode(), + $startLine, + $startIndex + ); case 'null': - return new Ast\ConstExpr\ConstExprNullNode(); + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprNullNode(), + $startLine, + $startIndex + ); case 'array': $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES); - return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_PARENTHESES); + return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_PARENTHESES, $startIndex); } if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) { @@ -106,29 +161,43 @@ class ConstExprParser break; } - return new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName); + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName), + $startLine, + $startIndex + ); } - return new Ast\ConstExpr\ConstFetchNode('', $identifier); + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstFetchNode('', $identifier), + $startLine, + $startIndex + ); } elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { - return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_SQUARE_BRACKET); + return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_SQUARE_BRACKET, $startIndex); } throw new ParserException( $tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), - Lexer::TOKEN_IDENTIFIER + Lexer::TOKEN_IDENTIFIER, + null, + $tokens->currentTokenLine() ); } - private function parseArray(TokenIterator $tokens, int $endToken): Ast\ConstExpr\ConstExprArrayNode + private function parseArray(TokenIterator $tokens, int $endToken, int $startIndex): Ast\ConstExpr\ConstExprArrayNode { $items = []; + $startLine = $tokens->currentTokenLine(); + if (!$tokens->tryConsumeTokenType($endToken)) { do { $items[] = $this->parseArrayItem($tokens); @@ -136,12 +205,20 @@ class ConstExprParser $tokens->consumeTokenType($endToken); } - return new Ast\ConstExpr\ConstExprArrayNode($items); + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprArrayNode($items), + $startLine, + $startIndex + ); } private function parseArrayItem(TokenIterator $tokens): Ast\ConstExpr\ConstExprArrayItemNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $expr = $this->parse($tokens); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_ARROW)) { @@ -153,78 +230,40 @@ class ConstExprParser $value = $expr; } - return new Ast\ConstExpr\ConstExprArrayItemNode($key, $value); - } - - private static function unescapeString(string $string): string - { - $quote = $string[0]; - - if ($quote === '\'') { - return str_replace( - ['\\\\', '\\\''], - ['\\', '\''], - substr($string, 1, -1) - ); - } - - return self::parseEscapeSequences(substr($string, 1, -1), '"'); - } - - /** - * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L90-L130 - */ - private static function parseEscapeSequences(string $str, string $quote): string - { - $str = str_replace('\\' . $quote, $quote, $str); - - return preg_replace_callback( - '~\\\\([\\\\nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}|u\{([0-9a-fA-F]+)\})~', - static function ($matches) { - $str = $matches[1]; - - if (isset(self::REPLACEMENTS[$str])) { - return self::REPLACEMENTS[$str]; - } - if ($str[0] === 'x' || $str[0] === 'X') { - return chr(hexdec(substr($str, 1))); - } - if ($str[0] === 'u') { - return self::codePointToUtf8(hexdec($matches[2])); - } - - return chr(octdec($str)); - }, - $str + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprArrayItemNode($key, $value), + $startLine, + $startIndex ); } /** - * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L132-L154 + * @template T of Ast\ConstExpr\ConstExprNode + * @param T $node + * @return T */ - private static function codePointToUtf8(int $num): string + private function enrichWithAttributes(TokenIterator $tokens, Ast\ConstExpr\ConstExprNode $node, int $startLine, int $startIndex): Ast\ConstExpr\ConstExprNode { - if ($num <= 0x7F) { - return chr($num); - } - if ($num <= 0x7FF) { - return chr(($num >> 6) + 0xC0) - . chr(($num & 0x3F) + 0x80); - } - if ($num <= 0xFFFF) { - return chr(($num >> 12) + 0xE0) - . chr((($num >> 6) & 0x3F) + 0x80) - . chr(($num & 0x3F) + 0x80); - } - if ($num <= 0x1FFFFF) { - return chr(($num >> 18) + 0xF0) - . chr((($num >> 12) & 0x3F) + 0x80) - . chr((($num >> 6) & 0x3F) + 0x80) - . chr(($num & 0x3F) + 0x80); + $endLine = $tokens->currentTokenLine(); + $endIndex = $tokens->currentTokenIndex(); + if ($this->useLinesAttributes) { + $node->setAttribute(Ast\Attribute::START_LINE, $startLine); + $node->setAttribute(Ast\Attribute::END_LINE, $endLine); } - // Invalid UTF-8 codepoint escape sequence: Codepoint too large - return "\xef\xbf\xbd"; + if ($this->useIndexAttributes) { + $tokensArray = $tokens->getTokens(); + $endIndex--; + if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { + $endIndex--; + } + + $node->setAttribute(Ast\Attribute::START_INDEX, $startIndex); + $node->setAttribute(Ast\Attribute::END_INDEX, $endIndex); + } + + return $node; } } diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php b/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php index badcdcbb..6ab5cc07 100644 --- a/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php +++ b/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php @@ -7,6 +7,7 @@ use PHPStan\PhpDocParser\Lexer\Lexer; use function assert; use function json_encode; use function sprintf; +use const JSON_INVALID_UTF8_SUBSTITUTE; use const JSON_UNESCAPED_SLASHES; use const JSON_UNESCAPED_UNICODE; @@ -28,12 +29,16 @@ class ParserException extends Exception /** @var string|null */ private $expectedTokenValue; + /** @var int|null */ + private $currentTokenLine; + public function __construct( string $currentTokenValue, int $currentTokenType, int $currentOffset, int $expectedTokenType, - ?string $expectedTokenValue = null + ?string $expectedTokenValue = null, + ?int $currentTokenLine = null ) { $this->currentTokenValue = $currentTokenValue; @@ -41,13 +46,15 @@ class ParserException extends Exception $this->currentOffset = $currentOffset; $this->expectedTokenType = $expectedTokenType; $this->expectedTokenValue = $expectedTokenValue; + $this->currentTokenLine = $currentTokenLine; parent::__construct(sprintf( - 'Unexpected token %s, expected %s%s at offset %d', + 'Unexpected token %s, expected %s%s at offset %d%s', $this->formatValue($currentTokenValue), Lexer::TOKEN_LABELS[$expectedTokenType], $expectedTokenValue !== null ? sprintf(' (%s)', $this->formatValue($expectedTokenValue)) : '', - $currentOffset + $currentOffset, + $currentTokenLine === null ? '' : sprintf(' on line %d', $currentTokenLine) )); } @@ -82,9 +89,15 @@ class ParserException extends Exception } + public function getCurrentTokenLine(): ?int + { + return $this->currentTokenLine; + } + + private function formatValue(string $value): string { - $json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + $json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE); assert($json !== false); return $json; diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php b/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php index d9942b3d..d3eed465 100644 --- a/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php +++ b/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php @@ -28,11 +28,32 @@ class PhpDocParser /** @var bool */ private $requireWhitespaceBeforeDescription; - public function __construct(TypeParser $typeParser, ConstExprParser $constantExprParser, bool $requireWhitespaceBeforeDescription = false) + /** @var bool */ + private $preserveTypeAliasesWithInvalidTypes; + + /** @var bool */ + private $useLinesAttributes; + + /** @var bool */ + private $useIndexAttributes; + + /** + * @param array{lines?: bool, indexes?: bool} $usedAttributes + */ + public function __construct( + TypeParser $typeParser, + ConstExprParser $constantExprParser, + bool $requireWhitespaceBeforeDescription = false, + bool $preserveTypeAliasesWithInvalidTypes = false, + array $usedAttributes = [] + ) { $this->typeParser = $typeParser; $this->constantExprParser = $constantExprParser; $this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription; + $this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes; + $this->useLinesAttributes = $usedAttributes['lines'] ?? false; + $this->useIndexAttributes = $usedAttributes['indexes'] ?? false; } @@ -54,30 +75,82 @@ class PhpDocParser $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PHPDOC); } catch (ParserException $e) { $name = ''; + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); if (count($children) > 0) { $lastChild = $children[count($children) - 1]; if ($lastChild instanceof Ast\PhpDoc\PhpDocTagNode) { $name = $lastChild->name; + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); } } + + $tag = new Ast\PhpDoc\PhpDocTagNode( + $name, + $this->enrichWithAttributes( + $tokens, + new Ast\PhpDoc\InvalidTagValueNode($e->getMessage(), $e), + $startLine, + $startIndex + ) + ); + $tokens->forwardToTheEnd(); - return new Ast\PhpDoc\PhpDocNode([ - new Ast\PhpDoc\PhpDocTagNode($name, new Ast\PhpDoc\InvalidTagValueNode($e->getMessage(), $e)), - ]); + + return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode([$this->enrichWithAttributes($tokens, $tag, $startLine, $startIndex)]), 1, 0); } - return new Ast\PhpDoc\PhpDocNode(array_values($children)); + return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode(array_values($children)), 1, 0); } private function parseChild(TokenIterator $tokens): Ast\PhpDoc\PhpDocChildNode { if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) { - return $this->parseTag($tokens); - + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + return $this->enrichWithAttributes($tokens, $this->parseTag($tokens), $startLine, $startIndex); } - return $this->parseText($tokens); + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $text = $this->parseText($tokens); + + return $this->enrichWithAttributes($tokens, $text, $startLine, $startIndex); + } + + /** + * @template T of Ast\Node + * @param T $tag + * @return T + */ + private function enrichWithAttributes(TokenIterator $tokens, Ast\Node $tag, int $startLine, int $startIndex): Ast\Node + { + $endLine = $tokens->currentTokenLine(); + $endIndex = $tokens->currentTokenIndex(); + + if ($this->useLinesAttributes) { + $tag->setAttribute(Ast\Attribute::START_LINE, $startLine); + $tag->setAttribute(Ast\Attribute::END_LINE, $endLine); + } + + if ($this->useIndexAttributes) { + $tokensArray = $tokens->getTokens(); + if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_CLOSE_PHPDOC) { + $endIndex--; + if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { + $endIndex--; + } + } elseif ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_PHPDOC_EOL) { + $endIndex--; + } + + $tag->setAttribute(Ast\Attribute::START_INDEX, $startIndex); + $tag->setAttribute(Ast\Attribute::END_INDEX, $endIndex); + } + + return $tag; } @@ -120,6 +193,9 @@ class PhpDocParser public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\PhpDocTagValueNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + try { $tokens->pushSavePoint(); @@ -247,7 +323,7 @@ class PhpDocParser $tagValue = new Ast\PhpDoc\InvalidTagValueNode($this->parseOptionalDescription($tokens), $e); } - return $tagValue; + return $this->enrichWithAttributes($tokens, $tagValue, $startLine, $startIndex); } @@ -257,9 +333,7 @@ class PhpDocParser private function parseParamTagValue(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode { if ( - $tokens->isCurrentTokenType(Lexer::TOKEN_REFERENCE) - || $tokens->isCurrentTokenType(Lexer::TOKEN_VARIADIC) - || $tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE) + $tokens->isCurrentTokenType(Lexer::TOKEN_REFERENCE, Lexer::TOKEN_VARIADIC, Lexer::TOKEN_VARIABLE) ) { $type = null; } else { @@ -329,6 +403,8 @@ class PhpDocParser private function parseMethodTagValue(TokenIterator $tokens): Ast\PhpDoc\MethodTagValueNode { $isStatic = $tokens->tryConsumeTokenValue('static'); + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); $returnTypeOrMethodName = $this->typeParser->parse($tokens); if ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { @@ -337,7 +413,9 @@ class PhpDocParser $tokens->next(); } elseif ($returnTypeOrMethodName instanceof Ast\Type\IdentifierTypeNode) { - $returnType = $isStatic ? new Ast\Type\IdentifierTypeNode('static') : null; + $returnType = $isStatic + ? $this->typeParser->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode('static'), $startLine, $startIndex) + : null; $methodName = $returnTypeOrMethodName->name; $isStatic = false; @@ -347,9 +425,12 @@ class PhpDocParser } $templateTypes = []; + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { do { - $templateTypes[] = $this->parseTemplateTagValue($tokens, false); + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $templateTypes[] = $this->enrichWithAttributes($tokens, $this->parseTemplateTagValue($tokens, false), $startLine, $startIndex); } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET); } @@ -370,6 +451,9 @@ class PhpDocParser private function parseMethodTagValueParameter(TokenIterator $tokens): Ast\PhpDoc\MethodTagValueParameterNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + switch ($tokens->currentTokenType()) { case Lexer::TOKEN_IDENTIFIER: case Lexer::TOKEN_OPEN_PARENTHESES: @@ -394,7 +478,12 @@ class PhpDocParser $defaultValue = null; } - return new Ast\PhpDoc\MethodTagValueParameterNode($parameterType, $isReference, $isVariadic, $parameterName, $defaultValue); + return $this->enrichWithAttributes( + $tokens, + new Ast\PhpDoc\MethodTagValueParameterNode($parameterType, $isReference, $isVariadic, $parameterName, $defaultValue), + $startLine, + $startIndex + ); } private function parseTemplateTagValue(TokenIterator $tokens, bool $parseDescription): Ast\PhpDoc\TemplateTagValueNode @@ -426,10 +515,15 @@ class PhpDocParser private function parseExtendsTagValue(string $tagName, TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); $baseType = new IdentifierTypeNode($tokens->currentTokenValue()); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); - $type = $this->typeParser->parseGeneric($tokens, $baseType); + $type = $this->typeParser->parseGeneric( + $tokens, + $this->typeParser->enrichWithAttributes($tokens, $baseType, $startLine, $startIndex) + ); $description = $this->parseOptionalDescription($tokens); @@ -453,6 +547,34 @@ class PhpDocParser // support psalm-type syntax $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL); + if ($this->preserveTypeAliasesWithInvalidTypes) { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + try { + $type = $this->typeParser->parse($tokens); + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { + throw new ParserException( + $tokens->currentTokenValue(), + $tokens->currentTokenType(), + $tokens->currentTokenOffset(), + Lexer::TOKEN_PHPDOC_EOL, + null, + $tokens->currentTokenLine() + ); + } + } + + return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type); + } catch (ParserException $e) { + $this->parseOptionalDescription($tokens); + return new Ast\PhpDoc\TypeAliasTagValueNode( + $alias, + $this->enrichWithAttributes($tokens, new Ast\Type\InvalidTypeNode($e), $startLine, $startIndex) + ); + } + } + $type = $this->typeParser->parse($tokens); return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type); @@ -465,8 +587,16 @@ class PhpDocParser $tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'from'); + $identifierStartLine = $tokens->currentTokenLine(); + $identifierStartIndex = $tokens->currentTokenIndex(); $importedFrom = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + $importedFromType = $this->enrichWithAttributes( + $tokens, + new IdentifierTypeNode($importedFrom), + $identifierStartLine, + $identifierStartIndex + ); $importedAs = null; if ($tokens->tryConsumeTokenValue('as')) { @@ -474,7 +604,7 @@ class PhpDocParser $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); } - return new Ast\PhpDoc\TypeAliasImportTagValueNode($importedAlias, new IdentifierTypeNode($importedFrom), $importedAs); + return new Ast\PhpDoc\TypeAliasImportTagValueNode($importedAlias, $importedFromType, $importedAs); } /** diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php b/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php new file mode 100644 index 00000000..70524055 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php @@ -0,0 +1,96 @@ + '\\', + 'n' => "\n", + 'r' => "\r", + 't' => "\t", + 'f' => "\f", + 'v' => "\v", + 'e' => "\x1B", + ]; + + public static function unescapeString(string $string): string + { + $quote = $string[0]; + + if ($quote === '\'') { + return str_replace( + ['\\\\', '\\\''], + ['\\', '\''], + substr($string, 1, -1) + ); + } + + return self::parseEscapeSequences(substr($string, 1, -1), '"'); + } + + /** + * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L90-L130 + */ + private static function parseEscapeSequences(string $str, string $quote): string + { + $str = str_replace('\\' . $quote, $quote, $str); + + return preg_replace_callback( + '~\\\\([\\\\nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}|u\{([0-9a-fA-F]+)\})~', + static function ($matches) { + $str = $matches[1]; + + if (isset(self::REPLACEMENTS[$str])) { + return self::REPLACEMENTS[$str]; + } + if ($str[0] === 'x' || $str[0] === 'X') { + return chr((int) hexdec(substr($str, 1))); + } + if ($str[0] === 'u') { + return self::codePointToUtf8((int) hexdec($matches[2])); + } + + return chr((int) octdec($str)); + }, + $str + ); + } + + /** + * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L132-L154 + */ + private static function codePointToUtf8(int $num): string + { + if ($num <= 0x7F) { + return chr($num); + } + if ($num <= 0x7FF) { + return chr(($num >> 6) + 0xC0) + . chr(($num & 0x3F) + 0x80); + } + if ($num <= 0xFFFF) { + return chr(($num >> 12) + 0xE0) + . chr((($num >> 6) & 0x3F) + 0x80) + . chr(($num & 0x3F) + 0x80); + } + if ($num <= 0x1FFFFF) { + return chr(($num >> 18) + 0xF0) + . chr((($num >> 12) & 0x3F) + 0x80) + . chr((($num >> 6) & 0x3F) + 0x80) + . chr(($num & 0x3F) + 0x80); + } + + // Invalid UTF-8 codepoint escape sequence: Codepoint too large + return "\xef\xbf\xbd"; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php b/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php index 569a9321..4348ab79 100644 --- a/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php +++ b/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php @@ -2,6 +2,7 @@ namespace PHPStan\PhpDocParser\Parser; +use LogicException; use PHPStan\PhpDocParser\Lexer\Lexer; use function array_pop; use function assert; @@ -12,7 +13,7 @@ use function strlen; class TokenIterator { - /** @var mixed[][] */ + /** @var list */ private $tokens; /** @var int */ @@ -21,6 +22,9 @@ class TokenIterator /** @var int[] */ private $savePoints = []; + /** + * @param list $tokens + */ public function __construct(array $tokens, int $index = 0) { $this->tokens = $tokens; @@ -34,6 +38,36 @@ class TokenIterator } + /** + * @return list + */ + public function getTokens(): array + { + return $this->tokens; + } + + + public function getContentBetween(int $startPos, int $endPos): string + { + if ($startPos < 0 || $endPos > count($this->tokens)) { + throw new LogicException(); + } + + $content = ''; + for ($i = $startPos; $i < $endPos; $i++) { + $content .= $this->tokens[$i][Lexer::VALUE_OFFSET]; + } + + return $content; + } + + + public function getTokenCount(): int + { + return count($this->tokens); + } + + public function currentTokenValue(): string { return $this->tokens[$this->index][Lexer::VALUE_OFFSET]; @@ -57,6 +91,18 @@ class TokenIterator } + public function currentTokenLine(): int + { + return $this->tokens[$this->index][Lexer::LINE_OFFSET]; + } + + + public function currentTokenIndex(): int + { + return $this->index; + } + + public function isCurrentTokenValue(string $tokenValue): bool { return $this->tokens[$this->index][Lexer::VALUE_OFFSET] === $tokenValue; @@ -217,8 +263,69 @@ class TokenIterator $this->currentTokenType(), $this->currentTokenOffset(), $expectedTokenType, - $expectedTokenValue + $expectedTokenValue, + $this->currentTokenLine() ); } + /** + * Check whether the position is directly preceded by a certain token type. + * + * During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped + */ + public function hasTokenImmediatelyBefore(int $pos, int $expectedTokenType): bool + { + $tokens = $this->tokens; + $pos--; + for (; $pos >= 0; $pos--) { + $token = $tokens[$pos]; + $type = $token[Lexer::TYPE_OFFSET]; + if ($type === $expectedTokenType) { + return true; + } + if (!in_array($type, [ + Lexer::TOKEN_HORIZONTAL_WS, + Lexer::TOKEN_PHPDOC_EOL, + ], true)) { + break; + } + } + return false; + } + + /** + * Check whether the position is directly followed by a certain token type. + * + * During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped + */ + public function hasTokenImmediatelyAfter(int $pos, int $expectedTokenType): bool + { + $tokens = $this->tokens; + $pos++; + for ($c = count($tokens); $pos < $c; $pos++) { + $token = $tokens[$pos]; + $type = $token[Lexer::TYPE_OFFSET]; + if ($type === $expectedTokenType) { + return true; + } + if (!in_array($type, [ + Lexer::TOKEN_HORIZONTAL_WS, + Lexer::TOKEN_PHPDOC_EOL, + ], true)) { + break; + } + } + + return false; + } + + /** + * Whether the given position is immediately surrounded by parenthesis. + */ + public function hasParentheses(int $startPos, int $endPos): bool + { + return $this->hasTokenImmediatelyBefore($startPos, Lexer::TOKEN_OPEN_PARENTHESES) + && $this->hasTokenImmediatelyAfter($endPos, Lexer::TOKEN_CLOSE_PARENTHESES); + } + } diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php b/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php index d196eb94..4b429809 100644 --- a/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php +++ b/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php @@ -6,6 +6,7 @@ use LogicException; use PHPStan\PhpDocParser\Ast; use PHPStan\PhpDocParser\Lexer\Lexer; use function in_array; +use function str_replace; use function strpos; use function trim; @@ -15,14 +16,35 @@ class TypeParser /** @var ConstExprParser|null */ private $constExprParser; - public function __construct(?ConstExprParser $constExprParser = null) + /** @var bool */ + private $quoteAwareConstExprString; + + /** @var bool */ + private $useLinesAttributes; + + /** @var bool */ + private $useIndexAttributes; + + /** + * @param array{lines?: bool, indexes?: bool} $usedAttributes + */ + public function __construct( + ?ConstExprParser $constExprParser = null, + bool $quoteAwareConstExprString = false, + array $usedAttributes = [] + ) { $this->constExprParser = $constExprParser; + $this->quoteAwareConstExprString = $quoteAwareConstExprString; + $this->useLinesAttributes = $usedAttributes['lines'] ?? false; + $this->useIndexAttributes = $usedAttributes['indexes'] ?? false; } /** @phpstan-impure */ public function parse(TokenIterator $tokens): Ast\Type\TypeNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) { $type = $this->parseNullable($tokens); @@ -37,12 +59,45 @@ class TypeParser } } + return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); + } + + /** + * @internal + * @template T of Ast\Node + * @param T $type + * @return T + */ + public function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex): Ast\Node + { + $endLine = $tokens->currentTokenLine(); + $endIndex = $tokens->currentTokenIndex(); + + if ($this->useLinesAttributes) { + $type->setAttribute(Ast\Attribute::START_LINE, $startLine); + $type->setAttribute(Ast\Attribute::END_LINE, $endLine); + } + + if ($this->useIndexAttributes) { + $tokensArray = $tokens->getTokens(); + $endIndex--; + if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { + $endIndex--; + } + + $type->setAttribute(Ast\Attribute::START_INDEX, $startIndex); + $type->setAttribute(Ast\Attribute::END_INDEX, $endIndex); + } + return $type; } /** @phpstan-impure */ private function subParse(TokenIterator $tokens): Ast\Type\TypeNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) { $type = $this->parseNullable($tokens); @@ -66,13 +121,16 @@ class TypeParser } } - return $type; + return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } /** @phpstan-impure */ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $type = $this->subParse($tokens); @@ -81,26 +139,26 @@ class TypeParser $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { - return $this->tryParseArrayOrOffsetAccess($tokens, $type); + $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); } - return $type; + return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } if ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) { - $type = new Ast\Type\ThisTypeNode(); + $type = $this->enrichWithAttributes($tokens, new Ast\Type\ThisTypeNode(), $startLine, $startIndex); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { - return $this->tryParseArrayOrOffsetAccess($tokens, $type); + $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); } - return $type; + return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } $currentTokenValue = $tokens->currentTokenValue(); $tokens->pushSavePoint(); // because of ConstFetchNode if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) { - $type = new Ast\Type\IdentifierTypeNode($currentTokenValue); + $type = $this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode($currentTokenValue), $startLine, $startIndex); if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) { $tokens->dropSavePoint(); // because of ConstFetchNode @@ -124,15 +182,22 @@ class TypeParser } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); - } elseif (in_array($type->name, ['array', 'list'], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) { - $type = $this->parseArrayShape($tokens, $type, $type->name); + } elseif (in_array($type->name, ['array', 'list', 'object'], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) { + if ($type->name === 'object') { + $type = $this->parseObjectShape($tokens); + } else { + $type = $this->parseArrayShape($tokens, $type, $type->name); + } if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { - $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); + $type = $this->tryParseArrayOrOffsetAccess( + $tokens, + $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex) + ); } } - return $type; + return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } else { $tokens->rollback(); // because of ConstFetchNode } @@ -144,7 +209,9 @@ class TypeParser $tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), - Lexer::TOKEN_IDENTIFIER + Lexer::TOKEN_IDENTIFIER, + null, + $tokens->currentTokenLine() ); if ($this->constExprParser === null) { @@ -157,7 +224,7 @@ class TypeParser throw $exception; } - return new Ast\Type\ConstTypeNode($constExpr); + return $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex); } catch (LogicException $e) { throw $exception; } @@ -336,7 +403,14 @@ class TypeParser $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) { // trailing comma case - return new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances); + $type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances); + $startLine = $baseType->getAttribute(Ast\Attribute::START_LINE); + $startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX); + if ($startLine !== null && $startIndex !== null) { + $type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); + } + + return $type; } [$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); @@ -345,7 +419,14 @@ class TypeParser $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET); - return new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances); + $type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances); + $startLine = $baseType->getAttribute(Ast\Attribute::START_LINE); + $startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX); + if ($startLine !== null && $startIndex !== null) { + $type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); + } + + return $type; } @@ -355,9 +436,11 @@ class TypeParser */ public function parseGenericTypeArgument(TokenIterator $tokens): array { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) { return [ - new Ast\Type\IdentifierTypeNode('mixed'), + $this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode('mixed'), $startLine, $startIndex), Ast\Type\GenericTypeNode::VARIANCE_BIVARIANT, ]; } @@ -397,7 +480,10 @@ class TypeParser $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); $tokens->consumeTokenType(Lexer::TOKEN_COLON); - $returnType = $this->parseCallableReturnType($tokens); + + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $returnType = $this->enrichWithAttributes($tokens, $this->parseCallableReturnType($tokens), $startLine, $startIndex); return new Ast\Type\CallableTypeNode($identifier, $parameters, $returnType); } @@ -406,6 +492,8 @@ class TypeParser /** @phpstan-impure */ private function parseCallableParameter(TokenIterator $tokens): Ast\Type\CallableTypeParameterNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); $type = $this->parse($tokens); $isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE); $isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC); @@ -419,37 +507,141 @@ class TypeParser } $isOptional = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL); - return new Ast\Type\CallableTypeParameterNode($type, $isReference, $isVariadic, $parameterName, $isOptional); + return $this->enrichWithAttributes( + $tokens, + new Ast\Type\CallableTypeParameterNode($type, $isReference, $isVariadic, $parameterName, $isOptional), + $startLine, + $startIndex + ); } /** @phpstan-impure */ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) { - $type = $this->parseNullable($tokens); + return $this->parseNullable($tokens); } elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { $type = $this->parse($tokens); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); + } + return $type; + } elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) { + $type = new Ast\Type\ThisTypeNode(); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + )); + } + + return $type; } else { - $type = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue()); - $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + $currentTokenValue = $tokens->currentTokenValue(); + $tokens->pushSavePoint(); // because of ConstFetchNode + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) { + $type = new Ast\Type\IdentifierTypeNode($currentTokenValue); - if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { - $type = $this->parseGeneric($tokens, $type); + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) { + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { + $type = $this->parseGeneric( + $tokens, + $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + ) + ); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + )); + } - } elseif (in_array($type->name, ['array', 'list'], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) { - $type = $this->parseArrayShape($tokens, $type, $type->name); + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + )); + + } elseif (in_array($type->name, ['array', 'list', 'object'], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) { + if ($type->name === 'object') { + $type = $this->parseObjectShape($tokens); + } else { + $type = $this->parseArrayShape($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + ), $type->name); + } + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + )); + } + } + + return $type; + } else { + $tokens->rollback(); // because of ConstFetchNode + } + } else { + $tokens->dropSavePoint(); // because of ConstFetchNode } } - if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { - $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); + $exception = new ParserException( + $tokens->currentTokenValue(), + $tokens->currentTokenType(), + $tokens->currentTokenOffset(), + Lexer::TOKEN_IDENTIFIER, + null, + $tokens->currentTokenLine() + ); + + if ($this->constExprParser === null) { + throw $exception; } - return $type; + try { + $constExpr = $this->constExprParser->parse($tokens, true); + if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { + throw $exception; + } + + $type = new Ast\Type\ConstTypeNode($constExpr); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + )); + } + + return $type; + } catch (LogicException $e) { + throw $exception; + } } @@ -473,6 +665,8 @@ class TypeParser /** @phpstan-impure */ private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode { + $startLine = $type->getAttribute(Ast\Attribute::START_LINE); + $startIndex = $type->getAttribute(Ast\Attribute::START_INDEX); try { while ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $tokens->pushSavePoint(); @@ -485,10 +679,28 @@ class TypeParser $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET); $tokens->dropSavePoint(); $type = new Ast\Type\OffsetAccessTypeNode($type, $offset); + + if ($startLine !== null && $startIndex !== null) { + $type = $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + ); + } } else { $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET); $tokens->dropSavePoint(); $type = new Ast\Type\ArrayTypeNode($type); + + if ($startLine !== null && $startIndex !== null) { + $type = $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + ); + } } } @@ -539,6 +751,8 @@ class TypeParser /** @phpstan-impure */ private function parseArrayShapeItem(TokenIterator $tokens): Ast\Type\ArrayShapeItemNode { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); try { $tokens->pushSavePoint(); $key = $this->parseArrayShapeKey($tokens); @@ -547,12 +761,22 @@ class TypeParser $value = $this->parse($tokens); $tokens->dropSavePoint(); - return new Ast\Type\ArrayShapeItemNode($key, $optional, $value); + return $this->enrichWithAttributes( + $tokens, + new Ast\Type\ArrayShapeItemNode($key, $optional, $value), + $startLine, + $startIndex + ); } catch (ParserException $e) { $tokens->rollback(); $value = $this->parse($tokens); - return new Ast\Type\ArrayShapeItemNode(null, false, $value); + return $this->enrichWithAttributes( + $tokens, + new Ast\Type\ArrayShapeItemNode(null, false, $value), + $startLine, + $startIndex + ); } } @@ -562,16 +786,28 @@ class TypeParser */ private function parseArrayShapeKey(TokenIterator $tokens) { + $startIndex = $tokens->currentTokenIndex(); + $startLine = $tokens->currentTokenLine(); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) { - $key = new Ast\ConstExpr\ConstExprIntegerNode($tokens->currentTokenValue()); + $key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue())); $tokens->next(); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) { - $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'")); + if ($this->quoteAwareConstExprString) { + $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED); + } else { + $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'")); + } $tokens->next(); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { - $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"')); + if ($this->quoteAwareConstExprString) { + $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED); + } else { + $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"')); + } + $tokens->next(); } else { @@ -579,7 +815,86 @@ class TypeParser $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); } - return $key; + return $this->enrichWithAttributes( + $tokens, + $key, + $startLine, + $startIndex + ); + } + + /** + * @phpstan-impure + */ + private function parseObjectShape(TokenIterator $tokens): Ast\Type\ObjectShapeNode + { + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET); + + $items = []; + + do { + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { + return new Ast\Type\ObjectShapeNode($items); + } + + $items[] = $this->parseObjectShapeItem($tokens); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET); + + return new Ast\Type\ObjectShapeNode($items); + } + + /** @phpstan-impure */ + private function parseObjectShapeItem(TokenIterator $tokens): Ast\Type\ObjectShapeItemNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + $key = $this->parseObjectShapeKey($tokens); + $optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE); + $tokens->consumeTokenType(Lexer::TOKEN_COLON); + $value = $this->parse($tokens); + + return $this->enrichWithAttributes($tokens, new Ast\Type\ObjectShapeItemNode($key, $optional, $value), $startLine, $startIndex); + } + + /** + * @phpstan-impure + * @return Ast\ConstExpr\ConstExprStringNode|Ast\Type\IdentifierTypeNode + */ + private function parseObjectShapeKey(TokenIterator $tokens) + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) { + if ($this->quoteAwareConstExprString) { + $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED); + } else { + $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'")); + } + $tokens->next(); + + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { + if ($this->quoteAwareConstExprString) { + $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED); + } else { + $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"')); + } + $tokens->next(); + + } else { + $key = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue()); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + } + + return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex); } } diff --git a/vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.php b/vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.php new file mode 100644 index 00000000..2684dfc7 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.php @@ -0,0 +1,44 @@ +type = $type; + $this->old = $old; + $this->new = $new; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php b/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php new file mode 100644 index 00000000..ab10be59 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php @@ -0,0 +1,196 @@ +isEqual = $isEqual; + } + + /** + * Calculate diff (edit script) from $old to $new. + * + * @param T[] $old Original array + * @param T[] $new New array + * + * @return DiffElem[] Diff (edit script) + */ + public function diff(array $old, array $new): array + { + [$trace, $x, $y] = $this->calculateTrace($old, $new); + return $this->extractDiff($trace, $x, $y, $old, $new); + } + + /** + * Calculate diff, including "replace" operations. + * + * If a sequence of remove operations is followed by the same number of add operations, these + * will be coalesced into replace operations. + * + * @param T[] $old Original array + * @param T[] $new New array + * + * @return DiffElem[] Diff (edit script), including replace operations + */ + public function diffWithReplacements(array $old, array $new): array + { + return $this->coalesceReplacements($this->diff($old, $new)); + } + + /** + * @param T[] $old + * @param T[] $new + * @return array{array>, int, int} + */ + private function calculateTrace(array $old, array $new): array + { + $n = count($old); + $m = count($new); + $max = $n + $m; + $v = [1 => 0]; + $trace = []; + for ($d = 0; $d <= $max; $d++) { + $trace[] = $v; + for ($k = -$d; $k <= $d; $k += 2) { + if ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) { + $x = $v[$k + 1]; + } else { + $x = $v[$k - 1] + 1; + } + + $y = $x - $k; + while ($x < $n && $y < $m && ($this->isEqual)($old[$x], $new[$y])) { + $x++; + $y++; + } + + $v[$k] = $x; + if ($x >= $n && $y >= $m) { + return [$trace, $x, $y]; + } + } + } + throw new Exception('Should not happen'); + } + + /** + * @param array> $trace + * @param T[] $old + * @param T[] $new + * @return DiffElem[] + */ + private function extractDiff(array $trace, int $x, int $y, array $old, array $new): array + { + $result = []; + for ($d = count($trace) - 1; $d >= 0; $d--) { + $v = $trace[$d]; + $k = $x - $y; + + if ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) { + $prevK = $k + 1; + } else { + $prevK = $k - 1; + } + + $prevX = $v[$prevK]; + $prevY = $prevX - $prevK; + + while ($x > $prevX && $y > $prevY) { + $result[] = new DiffElem(DiffElem::TYPE_KEEP, $old[$x - 1], $new[$y - 1]); + $x--; + $y--; + } + + if ($d === 0) { + break; + } + + while ($x > $prevX) { + $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $old[$x - 1], null); + $x--; + } + + while ($y > $prevY) { + $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $new[$y - 1]); + $y--; + } + } + return array_reverse($result); + } + + /** + * Coalesce equal-length sequences of remove+add into a replace operation. + * + * @param DiffElem[] $diff + * @return DiffElem[] + */ + private function coalesceReplacements(array $diff): array + { + $newDiff = []; + $c = count($diff); + for ($i = 0; $i < $c; $i++) { + $diffType = $diff[$i]->type; + if ($diffType !== DiffElem::TYPE_REMOVE) { + $newDiff[] = $diff[$i]; + continue; + } + + $j = $i; + while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) { + $j++; + } + + $k = $j; + while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) { + $k++; + } + + if ($j - $i === $k - $j) { + $len = $j - $i; + for ($n = 0; $n < $len; $n++) { + $newDiff[] = new DiffElem( + DiffElem::TYPE_REPLACE, + $diff[$i + $n]->old, + $diff[$j + $n]->new + ); + } + } else { + for (; $i < $k; $i++) { + $newDiff[] = $diff[$i]; + } + } + $i = $k - 1; + } + return $newDiff; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php b/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php new file mode 100644 index 00000000..bc07d10c --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php @@ -0,0 +1,796 @@ + */ + private $differ; + + /** + * Map From "{$class}->{$subNode}" to string that should be inserted + * between elements of this list subnode + * + * @var array + */ + private $listInsertionMap = [ + PhpDocNode::class . '->children' => "\n * ", + UnionTypeNode::class . '->types' => '|', + IntersectionTypeNode::class . '->types' => '&', + ArrayShapeNode::class . '->items' => ', ', + ObjectShapeNode::class . '->items' => ', ', + CallableTypeNode::class . '->parameters' => ', ', + GenericTypeNode::class . '->genericTypes' => ', ', + ConstExprArrayNode::class . '->items' => ', ', + MethodTagValueNode::class . '->parameters' => ', ', + ]; + + /** + * [$find, $extraLeft, $extraRight] + * + * @var array + */ + private $emptyListInsertionMap = [ + CallableTypeNode::class . '->parameters' => ['(', '', ''], + ArrayShapeNode::class . '->items' => ['{', '', ''], + ObjectShapeNode::class . '->items' => ['{', '', ''], + ]; + + /** @var array>> */ + private $parenthesesMap = [ + CallableTypeNode::class . '->returnType' => [ + CallableTypeNode::class, + UnionTypeNode::class, + IntersectionTypeNode::class, + ], + ArrayTypeNode::class . '->type' => [ + CallableTypeNode::class, + UnionTypeNode::class, + IntersectionTypeNode::class, + ConstTypeNode::class, + NullableTypeNode::class, + ], + OffsetAccessTypeNode::class . '->type' => [ + CallableTypeNode::class, + UnionTypeNode::class, + IntersectionTypeNode::class, + ConstTypeNode::class, + NullableTypeNode::class, + ], + ]; + + /** @var array>> */ + private $parenthesesListMap = [ + IntersectionTypeNode::class . '->types' => [ + IntersectionTypeNode::class, + UnionTypeNode::class, + NullableTypeNode::class, + ], + UnionTypeNode::class . '->types' => [ + IntersectionTypeNode::class, + UnionTypeNode::class, + NullableTypeNode::class, + ], + ]; + + public function printFormatPreserving(PhpDocNode $node, PhpDocNode $originalNode, TokenIterator $originalTokens): string + { + $this->differ = new Differ(static function ($a, $b) { + if ($a instanceof Node && $b instanceof Node) { + return $a === $b->getAttribute(Attribute::ORIGINAL_NODE); + } + + return false; + }); + + $tokenIndex = 0; + $result = $this->printArrayFormatPreserving( + $node->children, + $originalNode->children, + $originalTokens, + $tokenIndex, + PhpDocNode::class, + 'children' + ); + if ($result !== null) { + return $result . $originalTokens->getContentBetween($tokenIndex, $originalTokens->getTokenCount()); + } + + return $this->print($node); + } + + public function print(Node $node): string + { + if ($node instanceof PhpDocNode) { + return "/**\n *" . implode("\n *", array_map( + function (PhpDocChildNode $child): string { + $s = $this->print($child); + return $s === '' ? '' : ' ' . $s; + }, + $node->children + )) . "\n */"; + } + if ($node instanceof PhpDocTextNode) { + return $node->text; + } + if ($node instanceof PhpDocTagNode) { + return trim(sprintf('%s %s', $node->name, $this->print($node->value))); + } + if ($node instanceof PhpDocTagValueNode) { + return $this->printTagValue($node); + } + if ($node instanceof TypeNode) { + return $this->printType($node); + } + if ($node instanceof ConstExprNode) { + return $this->printConstExpr($node); + } + if ($node instanceof MethodTagValueParameterNode) { + $type = $node->type !== null ? $this->print($node->type) . ' ' : ''; + $isReference = $node->isReference ? '&' : ''; + $isVariadic = $node->isVariadic ? '...' : ''; + $default = $node->defaultValue !== null ? ' = ' . $this->print($node->defaultValue) : ''; + return "{$type}{$isReference}{$isVariadic}{$node->parameterName}{$default}"; + } + if ($node instanceof CallableTypeParameterNode) { + $type = $this->print($node->type) . ' '; + $isReference = $node->isReference ? '&' : ''; + $isVariadic = $node->isVariadic ? '...' : ''; + $isOptional = $node->isOptional ? '=' : ''; + return trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional; + } + + throw new LogicException(sprintf('Unknown node type %s', get_class($node))); + } + + private function printTagValue(PhpDocTagValueNode $node): string + { + // only nodes that contain another node are handled here + // the rest falls back on (string) $node + + if ($node instanceof AssertTagMethodValueNode) { + $isNegated = $node->isNegated ? '!' : ''; + $isEquality = $node->isEquality ? '=' : ''; + $type = $this->printType($node->type); + return trim("{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->method}() {$node->description}"); + } + if ($node instanceof AssertTagPropertyValueNode) { + $isNegated = $node->isNegated ? '!' : ''; + $isEquality = $node->isEquality ? '=' : ''; + $type = $this->printType($node->type); + return trim("{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->property} {$node->description}"); + } + if ($node instanceof AssertTagValueNode) { + $isNegated = $node->isNegated ? '!' : ''; + $isEquality = $node->isEquality ? '=' : ''; + $type = $this->printType($node->type); + return trim("{$isNegated}{$isEquality}{$type} {$node->parameter} {$node->description}"); + } + if ($node instanceof ExtendsTagValueNode || $node instanceof ImplementsTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->description}"); + } + if ($node instanceof MethodTagValueNode) { + $static = $node->isStatic ? 'static ' : ''; + $returnType = $node->returnType !== null ? $this->printType($node->returnType) . ' ' : ''; + $parameters = implode(', ', array_map(function (MethodTagValueParameterNode $parameter): string { + return $this->print($parameter); + }, $node->parameters)); + $description = $node->description !== '' ? " {$node->description}" : ''; + $templateTypes = count($node->templateTypes) > 0 ? '<' . implode(', ', array_map(function (TemplateTagValueNode $templateTag): string { + return $this->print($templateTag); + }, $node->templateTypes)) . '>' : ''; + return "{$static}{$returnType}{$node->methodName}{$templateTypes}({$parameters}){$description}"; + } + if ($node instanceof MixinTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->description}"); + } + if ($node instanceof ParamOutTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->parameterName} {$node->description}"); + } + if ($node instanceof ParamTagValueNode) { + $reference = $node->isReference ? '&' : ''; + $variadic = $node->isVariadic ? '...' : ''; + $type = $this->printType($node->type); + return trim("{$type} {$reference}{$variadic}{$node->parameterName} {$node->description}"); + } + if ($node instanceof PropertyTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->propertyName} {$node->description}"); + } + if ($node instanceof ReturnTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->description}"); + } + if ($node instanceof SelfOutTagValueNode) { + $type = $this->printType($node->type); + return trim($type . ' ' . $node->description); + } + if ($node instanceof TemplateTagValueNode) { + $bound = $node->bound !== null ? ' of ' . $this->printType($node->bound) : ''; + $default = $node->default !== null ? ' = ' . $this->printType($node->default) : ''; + return trim("{$node->name}{$bound}{$default} {$node->description}"); + } + if ($node instanceof ThrowsTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->description}"); + } + if ($node instanceof TypeAliasImportTagValueNode) { + return trim( + "{$node->importedAlias} from " . $this->printType($node->importedFrom) + . ($node->importedAs !== null ? " as {$node->importedAs}" : '') + ); + } + if ($node instanceof TypeAliasTagValueNode) { + $type = $this->printType($node->type); + return trim("{$node->alias} {$type}"); + } + if ($node instanceof UsesTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->description}"); + } + if ($node instanceof VarTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} " . trim("{$node->variableName} {$node->description}")); + } + + return (string) $node; + } + + private function printType(TypeNode $node): string + { + if ($node instanceof ArrayShapeNode) { + $items = array_map(function (ArrayShapeItemNode $item): string { + return $this->printType($item); + }, $node->items); + + if (! $node->sealed) { + $items[] = '...'; + } + + return $node->kind . '{' . implode(', ', $items) . '}'; + } + if ($node instanceof ArrayShapeItemNode) { + if ($node->keyName !== null) { + return sprintf( + '%s%s: %s', + $this->print($node->keyName), + $node->optional ? '?' : '', + $this->printType($node->valueType) + ); + } + + return $this->printType($node->valueType); + } + if ($node instanceof ArrayTypeNode) { + return $this->printOffsetAccessType($node->type) . '[]'; + } + if ($node instanceof CallableTypeNode) { + if ($node->returnType instanceof CallableTypeNode || $node->returnType instanceof UnionTypeNode || $node->returnType instanceof IntersectionTypeNode) { + $returnType = $this->wrapInParentheses($node->returnType); + } else { + $returnType = $this->printType($node->returnType); + } + $parameters = implode(', ', array_map(function (CallableTypeParameterNode $parameterNode): string { + return $this->print($parameterNode); + }, $node->parameters)); + return "{$node->identifier}({$parameters}): {$returnType}"; + } + if ($node instanceof ConditionalTypeForParameterNode) { + return sprintf( + '(%s %s %s ? %s : %s)', + $node->parameterName, + $node->negated ? 'is not' : 'is', + $this->printType($node->targetType), + $this->printType($node->if), + $this->printType($node->else) + ); + } + if ($node instanceof ConditionalTypeNode) { + return sprintf( + '(%s %s %s ? %s : %s)', + $this->printType($node->subjectType), + $node->negated ? 'is not' : 'is', + $this->printType($node->targetType), + $this->printType($node->if), + $this->printType($node->else) + ); + } + if ($node instanceof ConstTypeNode) { + return $this->printConstExpr($node->constExpr); + } + if ($node instanceof GenericTypeNode) { + $genericTypes = []; + + foreach ($node->genericTypes as $index => $type) { + $variance = $node->variances[$index] ?? GenericTypeNode::VARIANCE_INVARIANT; + if ($variance === GenericTypeNode::VARIANCE_INVARIANT) { + $genericTypes[] = $this->printType($type); + } elseif ($variance === GenericTypeNode::VARIANCE_BIVARIANT) { + $genericTypes[] = '*'; + } else { + $genericTypes[] = sprintf('%s %s', $variance, $this->print($type)); + } + } + + return $node->type . '<' . implode(', ', $genericTypes) . '>'; + } + if ($node instanceof IdentifierTypeNode) { + return $node->name; + } + if ($node instanceof IntersectionTypeNode || $node instanceof UnionTypeNode) { + $items = []; + foreach ($node->types as $type) { + if ( + $type instanceof IntersectionTypeNode + || $type instanceof UnionTypeNode + || $type instanceof NullableTypeNode + ) { + $items[] = $this->wrapInParentheses($type); + continue; + } + + $items[] = $this->printType($type); + } + + return implode($node instanceof IntersectionTypeNode ? '&' : '|', $items); + } + if ($node instanceof InvalidTypeNode) { + return (string) $node; + } + if ($node instanceof NullableTypeNode) { + if ($node->type instanceof IntersectionTypeNode || $node->type instanceof UnionTypeNode) { + return '?(' . $this->printType($node->type) . ')'; + } + + return '?' . $this->printType($node->type); + } + if ($node instanceof ObjectShapeNode) { + $items = array_map(function (ObjectShapeItemNode $item): string { + return $this->printType($item); + }, $node->items); + + return 'object{' . implode(', ', $items) . '}'; + } + if ($node instanceof ObjectShapeItemNode) { + if ($node->keyName !== null) { + return sprintf( + '%s%s: %s', + $this->print($node->keyName), + $node->optional ? '?' : '', + $this->printType($node->valueType) + ); + } + + return $this->printType($node->valueType); + } + if ($node instanceof OffsetAccessTypeNode) { + return $this->printOffsetAccessType($node->type) . '[' . $this->printType($node->offset) . ']'; + } + if ($node instanceof ThisTypeNode) { + return (string) $node; + } + + throw new LogicException(sprintf('Unknown node type %s', get_class($node))); + } + + private function wrapInParentheses(TypeNode $node): string + { + return '(' . $this->printType($node) . ')'; + } + + private function printOffsetAccessType(TypeNode $type): string + { + if ( + $type instanceof CallableTypeNode + || $type instanceof UnionTypeNode + || $type instanceof IntersectionTypeNode + || $type instanceof ConstTypeNode + || $type instanceof NullableTypeNode + ) { + return $this->wrapInParentheses($type); + } + + return $this->printType($type); + } + + private function printConstExpr(ConstExprNode $node): string + { + // this is fine - ConstExprNode classes do not contain nodes that need smart printer logic + return (string) $node; + } + + /** + * @param Node[] $nodes + * @param Node[] $originalNodes + */ + private function printArrayFormatPreserving(array $nodes, array $originalNodes, TokenIterator $originalTokens, int &$tokenIndex, string $parentNodeClass, string $subNodeName): ?string + { + $diff = $this->differ->diffWithReplacements($originalNodes, $nodes); + $mapKey = $parentNodeClass . '->' . $subNodeName; + $insertStr = $this->listInsertionMap[$mapKey] ?? null; + $result = ''; + $beforeFirstKeepOrReplace = true; + $delayedAdd = []; + + $insertNewline = false; + [$isMultiline, $beforeAsteriskIndent, $afterAsteriskIndent] = $this->isMultiline($tokenIndex, $originalNodes, $originalTokens); + + if ($insertStr === "\n * ") { + $insertStr = sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + } + + foreach ($diff as $i => $diffElem) { + $diffType = $diffElem->type; + $newNode = $diffElem->new; + $originalNode = $diffElem->old; + if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) { + $beforeFirstKeepOrReplace = false; + if (!$newNode instanceof Node || !$originalNode instanceof Node) { + return null; + } + $itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX); + $itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX); + if ($itemStartPos < 0 || $itemEndPos < 0 || $itemStartPos < $tokenIndex) { + throw new LogicException(); + } + + $result .= $originalTokens->getContentBetween($tokenIndex, $itemStartPos); + + if (count($delayedAdd) > 0) { + foreach ($delayedAdd as $delayedAddNode) { + $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) + && in_array(get_class($delayedAddNode), $this->parenthesesListMap[$mapKey], true); + if ($parenthesesNeeded) { + $result .= '('; + } + $result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens); + if ($parenthesesNeeded) { + $result .= ')'; + } + + if ($insertNewline) { + $result .= $insertStr . sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + } else { + $result .= $insertStr; + } + } + + $delayedAdd = []; + } + + $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) + && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], true); + $addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($itemStartPos, $itemEndPos); + if ($addParentheses) { + $result .= '('; + } + + $result .= $this->printNodeFormatPreserving($newNode, $originalTokens); + if ($addParentheses) { + $result .= ')'; + } + $tokenIndex = $itemEndPos + 1; + + } elseif ($diffType === DiffElem::TYPE_ADD) { + if ($insertStr === null) { + return null; + } + if (!$newNode instanceof Node) { + return null; + } + + if ($insertStr === ', ' && $isMultiline) { + $insertStr = ','; + $insertNewline = true; + } + + if ($beforeFirstKeepOrReplace) { + // Will be inserted at the next "replace" or "keep" element + $delayedAdd[] = $newNode; + continue; + } + + $itemEndPos = $tokenIndex - 1; + if ($insertNewline) { + $result .= $insertStr . sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + } else { + $result .= $insertStr; + } + + $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) + && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], true); + if ($parenthesesNeeded) { + $result .= '('; + } + + $result .= $this->printNodeFormatPreserving($newNode, $originalTokens); + if ($parenthesesNeeded) { + $result .= ')'; + } + + $tokenIndex = $itemEndPos + 1; + + } elseif ($diffType === DiffElem::TYPE_REMOVE) { + if (!$originalNode instanceof Node) { + return null; + } + + $itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX); + $itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX); + if ($itemStartPos < 0 || $itemEndPos < 0) { + throw new LogicException(); + } + + if ($i === 0) { + // If we're removing from the start, keep the tokens before the node and drop those after it, + // instead of the other way around. + $originalTokensArray = $originalTokens->getTokens(); + for ($j = $tokenIndex; $j < $itemStartPos; $j++) { + if ($originalTokensArray[$j][Lexer::TYPE_OFFSET] === Lexer::TOKEN_PHPDOC_EOL) { + break; + } + $result .= $originalTokensArray[$j][Lexer::VALUE_OFFSET]; + } + } + + $tokenIndex = $itemEndPos + 1; + } + } + + if (count($delayedAdd) > 0) { + if (!isset($this->emptyListInsertionMap[$mapKey])) { + return null; + } + + [$findToken, $extraLeft, $extraRight] = $this->emptyListInsertionMap[$mapKey]; + if ($findToken !== null) { + $originalTokensArray = $originalTokens->getTokens(); + for (; $tokenIndex < count($originalTokensArray); $tokenIndex++) { + $result .= $originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET]; + if ($originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET] !== $findToken) { + continue; + } + + $tokenIndex++; + break; + } + } + $first = true; + $result .= $extraLeft; + foreach ($delayedAdd as $delayedAddNode) { + if (!$first) { + $result .= $insertStr; + if ($insertNewline) { + $result .= sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + } + } + + $result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens); + $first = false; + } + $result .= $extraRight; + } + + return $result; + } + + /** + * @param Node[] $nodes + * @return array{bool, string, string} + */ + private function isMultiline(int $initialIndex, array $nodes, TokenIterator $originalTokens): array + { + $isMultiline = count($nodes) > 1; + $pos = $initialIndex; + $allText = ''; + /** @var Node|null $node */ + foreach ($nodes as $node) { + if (!$node instanceof Node) { + continue; + } + + $endPos = $node->getAttribute(Attribute::END_INDEX) + 1; + $text = $originalTokens->getContentBetween($pos, $endPos); + $allText .= $text; + if (strpos($text, "\n") === false) { + // We require that a newline is present between *every* item. If the formatting + // is inconsistent, with only some items having newlines, we don't consider it + // as multiline + $isMultiline = false; + } + $pos = $endPos; + } + + $c = preg_match_all('~\n(?[\\x09\\x20]*)\*(?\\x20*)~', $allText, $matches, PREG_SET_ORDER); + if ($c === 0) { + return [$isMultiline, '', '']; + } + + $before = ''; + $after = ''; + foreach ($matches as $match) { + if (strlen($match['before']) > strlen($before)) { + $before = $match['before']; + } + if (strlen($match['after']) <= strlen($after)) { + continue; + } + + $after = $match['after']; + } + + return [$isMultiline, $before, $after]; + } + + private function printNodeFormatPreserving(Node $node, TokenIterator $originalTokens): string + { + /** @var Node|null $originalNode */ + $originalNode = $node->getAttribute(Attribute::ORIGINAL_NODE); + if ($originalNode === null) { + return $this->print($node); + } + + $class = get_class($node); + if ($class !== get_class($originalNode)) { + throw new LogicException(); + } + + $startPos = $originalNode->getAttribute(Attribute::START_INDEX); + $endPos = $originalNode->getAttribute(Attribute::END_INDEX); + if ($startPos < 0 || $endPos < 0) { + throw new LogicException(); + } + + $result = ''; + $pos = $startPos; + $subNodeNames = array_keys(get_object_vars($node)); + foreach ($subNodeNames as $subNodeName) { + $subNode = $node->$subNodeName; + $origSubNode = $originalNode->$subNodeName; + + if ( + (!$subNode instanceof Node && $subNode !== null) + || (!$origSubNode instanceof Node && $origSubNode !== null) + ) { + if ($subNode === $origSubNode) { + // Unchanged, can reuse old code + continue; + } + + if (is_array($subNode) && is_array($origSubNode)) { + // Array subnode changed, we might be able to reconstruct it + $listResult = $this->printArrayFormatPreserving( + $subNode, + $origSubNode, + $originalTokens, + $pos, + $class, + $subNodeName + ); + + if ($listResult === null) { + return $this->print($node); + } + + $result .= $listResult; + continue; + } + + return $this->print($node); + } + + if ($origSubNode === null) { + if ($subNode === null) { + // Both null, nothing to do + continue; + } + + return $this->print($node); + } + + $subStartPos = $origSubNode->getAttribute(Attribute::START_INDEX); + $subEndPos = $origSubNode->getAttribute(Attribute::END_INDEX); + if ($subStartPos < 0 || $subEndPos < 0) { + throw new LogicException(); + } + + if ($subNode === null) { + return $this->print($node); + } + + $result .= $originalTokens->getContentBetween($pos, $subStartPos); + $mapKey = get_class($node) . '->' . $subNodeName; + $parenthesesNeeded = isset($this->parenthesesMap[$mapKey]) + && in_array(get_class($subNode), $this->parenthesesMap[$mapKey], true); + $addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($subStartPos, $subEndPos); + if ($addParentheses) { + $result .= '('; + } + + $result .= $this->printNodeFormatPreserving($subNode, $originalTokens); + if ($addParentheses) { + $result .= ')'; + } + + $pos = $subEndPos + 1; + } + + return $result . $originalTokens->getContentBetween($pos, $endPos + 1); + } + +} diff --git a/vendor/phpstan/phpstan/bootstrap.php b/vendor/phpstan/phpstan/bootstrap.php index 204221a3..1537f3f1 100644 --- a/vendor/phpstan/phpstan/bootstrap.php +++ b/vendor/phpstan/phpstan/bootstrap.php @@ -23,7 +23,6 @@ final class PharAutoloader self::$composerAutoloader = require 'phar://' . __DIR__ . '/phpstan.phar/vendor/autoload.php'; require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/jetbrains/phpstorm-stubs/PhpStormStubsMap.php'; require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/async/src/functions_include.php'; - require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/promise-stream/src/functions_include.php'; require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/promise-timer/src/functions_include.php'; require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/promise/src/functions_include.php'; require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/ringcentral/psr7/src/functions_include.php'; diff --git a/vendor/phpstan/phpstan/phpstan.phar b/vendor/phpstan/phpstan/phpstan.phar index 947d5ab020763ed0cc67902dcde0f7016a29a2a4..3f043c719c2bf287748aa89742f06c0273027c0e 100755 GIT binary patch delta 405041 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ĜxYriw8dGEZz`R;UyjG~ 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 K&-l?(M*n}y_j$em delta 367104 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

LQ)Az==C3n4@NMv9<6Sc{(Q?SE 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�ygli+P8MLlYXGlY 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

x&g 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 $prev[$j + 1]) { + $current[$j + 1] = $current[$j]; + } else { + $current[$j + 1] = $prev[$j + 1]; + } } } } diff --git a/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php b/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php index 51bac1f1..93b76288 100644 --- a/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php +++ b/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php @@ -37,12 +37,24 @@ final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCo for ($i = 1; $i <= $fromLength; $i++) { for ($j = 1; $j <= $toLength; $j++) { - $o = ($j * $width) + $i; - $matrix[$o] = max( - $matrix[$o - 1], - $matrix[$o - $width], - $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0 - ); + $o = ($j * $width) + $i; + + // don't use max() to avoid function call overhead + $firstOrLast = $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0; + + if ($matrix[$o - 1] > $matrix[$o - $width]) { + if ($firstOrLast > $matrix[$o - 1]) { + $matrix[$o] = $firstOrLast; + } else { + $matrix[$o] = $matrix[$o - 1]; + } + } else { + if ($firstOrLast > $matrix[$o - $width]) { + $matrix[$o] = $firstOrLast; + } else { + $matrix[$o] = $matrix[$o - $width]; + } + } } } diff --git a/vendor/spatie/array-to-xml/CHANGELOG.md b/vendor/spatie/array-to-xml/CHANGELOG.md index d43177a4..0a086699 100755 --- a/vendor/spatie/array-to-xml/CHANGELOG.md +++ b/vendor/spatie/array-to-xml/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to `array-to-xml` will be documented in this file +## 3.1.5 - 2022-12-24 + +### What's Changed + +- Add Dependabot Automation by @patinthehat in https://github.com/spatie/array-to-xml/pull/196 +- Bump actions/checkout from 2 to 3 by @dependabot in https://github.com/spatie/array-to-xml/pull/197 +- Fix PHP version by @parallels999 in https://github.com/spatie/array-to-xml/pull/198 +- fix deprecated `passing null as string type` by @trin4ik in https://github.com/spatie/array-to-xml/pull/204 + +### New Contributors + +- @dependabot made their first contribution in https://github.com/spatie/array-to-xml/pull/197 +- @parallels999 made their first contribution in https://github.com/spatie/array-to-xml/pull/198 +- @trin4ik made their first contribution in https://github.com/spatie/array-to-xml/pull/204 + +**Full Changelog**: https://github.com/spatie/array-to-xml/compare/3.1.4...3.1.5 + ## 3.1.4 - 2022-11-24 ### What's Changed diff --git a/vendor/spatie/array-to-xml/README.md b/vendor/spatie/array-to-xml/README.md index 5d4769a3..ec6a6ad8 100755 --- a/vendor/spatie/array-to-xml/README.md +++ b/vendor/spatie/array-to-xml/README.md @@ -1,6 +1,3 @@ - -[](https://supportukrainenow.org) - # Convert an array to xml [![Latest Version](https://img.shields.io/github/release/spatie/array-to-xml.svg?style=flat-square)](https://github.com/spatie/array-to-xml/releases) diff --git a/vendor/spatie/array-to-xml/src/ArrayToXml.php b/vendor/spatie/array-to-xml/src/ArrayToXml.php index e08a150d..b84bdc86 100644 --- a/vendor/spatie/array-to-xml/src/ArrayToXml.php +++ b/vendor/spatie/array-to-xml/src/ArrayToXml.php @@ -24,7 +24,8 @@ class ArrayToXml string | null $xmlEncoding = null, string $xmlVersion = '1.0', array $domProperties = [], - bool | null $xmlStandalone = null + bool | null $xmlStandalone = null, + bool $addXmlDeclaration = true ) { $this->document = new DOMDocument($xmlVersion, $xmlEncoding ?? ''); @@ -36,6 +37,8 @@ class ArrayToXml $this->setDomProperties($domProperties); } + $this->addXmlDeclaration = $addXmlDeclaration; + $this->replaceSpacesByUnderScoresInKeyNames = $replaceSpacesByUnderScoresInKeyNames; if (! empty($array) && $this->isArrayAllKeySequential($array)) { @@ -61,7 +64,8 @@ class ArrayToXml string $xmlEncoding = null, string $xmlVersion = '1.0', array $domProperties = [], - bool $xmlStandalone = null + bool $xmlStandalone = null, + bool $addXmlDeclaration = true, ): string { $converter = new static( $array, @@ -70,7 +74,8 @@ class ArrayToXml $xmlEncoding, $xmlVersion, $domProperties, - $xmlStandalone + $xmlStandalone, + $addXmlDeclaration ); return $converter->toXml(); @@ -80,7 +85,7 @@ class ArrayToXml { return $this->addXmlDeclaration ? $this->document->saveXML() - : $this->document->saveXml($this->document->documentElement); + : $this->document->saveXML($this->document->documentElement); } public function toDom(): DOMDocument diff --git a/vendor/symfony/console/Command/CompleteCommand.php b/vendor/symfony/console/Command/CompleteCommand.php index e65b334c..dbf5d7dd 100644 --- a/vendor/symfony/console/Command/CompleteCommand.php +++ b/vendor/symfony/console/Command/CompleteCommand.php @@ -173,10 +173,10 @@ final class CompleteCommand extends Command throw $e; } - return self::FAILURE; + return 2; } - return self::SUCCESS; + return 0; } private function createCompletionInput(InputInterface $input): CompletionInput diff --git a/vendor/symfony/console/Command/DumpCompletionCommand.php b/vendor/symfony/console/Command/DumpCompletionCommand.php index 1ad1c0e7..cac944ec 100644 --- a/vendor/symfony/console/Command/DumpCompletionCommand.php +++ b/vendor/symfony/console/Command/DumpCompletionCommand.php @@ -48,14 +48,16 @@ final class DumpCompletionCommand extends Command $shell = $this->guessShell(); [$rcFile, $completionFile] = match ($shell) { 'fish' => ['~/.config/fish/config.fish', "/etc/fish/completions/$commandName.fish"], - 'zsh' => ['~/.zshrc', '$fpath[1]/'.$commandName], + 'zsh' => ['~/.zshrc', '$fpath[1]/_'.$commandName], default => ['~/.bashrc', "/etc/bash_completion.d/$commandName"], }; + $supportedShells = implode(', ', $this->getSupportedShells()); + $this ->setHelp(<<%command.name% command dumps the shell completion script required -to use shell autocompletion (currently, bash and fish completion is supported). +to use shell autocompletion (currently, {$supportedShells} completion are supported). Static installation ------------------- @@ -94,7 +96,7 @@ EOH if ($input->getOption('debug')) { $this->tailDebugLog($commandName, $output); - return self::SUCCESS; + return 0; } $shell = $input->getArgument('shell') ?? self::guessShell(); @@ -111,12 +113,12 @@ EOH $output->writeln(sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); } - return self::INVALID; + return 2; } $output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, CompleteCommand::COMPLETION_API_VERSION], file_get_contents($completionFile))); - return self::SUCCESS; + return 0; } private static function guessShell(): string @@ -141,8 +143,19 @@ EOH */ private function getSupportedShells(): array { - return $this->supportedShells ??= array_map(function ($f) { - return pathinfo($f, \PATHINFO_EXTENSION); - }, glob(__DIR__.'/../Resources/completion.*')); + if (isset($this->supportedShells)) { + return $this->supportedShells; + } + + $shells = []; + + foreach (new \DirectoryIterator(__DIR__.'/../Resources/') as $file) { + if (str_starts_with($file->getBasename(), 'completion.') && $file->isFile()) { + $shells[] = $file->getExtension(); + } + } + sort($shells); + + return $this->supportedShells = $shells; } } diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyle.php b/vendor/symfony/console/Formatter/OutputFormatterStyle.php index 1659986e..3394c9ad 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterStyle.php +++ b/vendor/symfony/console/Formatter/OutputFormatterStyle.php @@ -83,7 +83,8 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface public function apply(string $text): string { $this->handlesHrefGracefully ??= 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR') - && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100); + && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100) + && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']); if (null !== $this->href && $this->handlesHrefGracefully) { $text = "\033]8;;$this->href\033\\$text\033]8;;\033\\"; diff --git a/vendor/symfony/console/Helper/QuestionHelper.php b/vendor/symfony/console/Helper/QuestionHelper.php index c345b4af..f26ca577 100644 --- a/vendor/symfony/console/Helper/QuestionHelper.php +++ b/vendor/symfony/console/Helper/QuestionHelper.php @@ -123,7 +123,18 @@ class QuestionHelper extends Helper } if (false === $ret) { + $isBlocked = stream_get_meta_data($inputStream)['blocked'] ?? true; + + if (!$isBlocked) { + stream_set_blocking($inputStream, true); + } + $ret = $this->readInput($inputStream, $question); + + if (!$isBlocked) { + stream_set_blocking($inputStream, false); + } + if (false === $ret) { throw new MissingInputException('Aborted.'); } @@ -496,13 +507,11 @@ class QuestionHelper extends Helper return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r')); } - if (!\function_exists('exec')) { + if (!\function_exists('shell_exec')) { return self::$stdinIsInteractive = true; } - exec('stty 2> /dev/null', $output, $status); - - return self::$stdinIsInteractive = 1 !== $status; + return self::$stdinIsInteractive = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } /** diff --git a/vendor/symfony/console/Helper/Table.php b/vendor/symfony/console/Helper/Table.php index 893b3192..907c9f50 100644 --- a/vendor/symfony/console/Helper/Table.php +++ b/vendor/symfony/console/Helper/Table.php @@ -804,7 +804,7 @@ class Table $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); $textLength = Helper::width($textContent); if ($textLength > 0) { - $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan())); + $contentColumns = mb_str_split($textContent, ceil($textLength / $cell->getColspan())); foreach ($contentColumns as $position => $content) { $row[$i + $position] = $content; } diff --git a/vendor/symfony/console/Input/InputArgument.php b/vendor/symfony/console/Input/InputArgument.php index a130c412..0e86e916 100644 --- a/vendor/symfony/console/Input/InputArgument.php +++ b/vendor/symfony/console/Input/InputArgument.php @@ -37,7 +37,7 @@ class InputArgument /** * @param string $name The argument name - * @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL + * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY * @param string $description A description text * @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion diff --git a/vendor/symfony/console/Resources/completion.zsh b/vendor/symfony/console/Resources/completion.zsh index 97a9e88c..ff76fe5f 100644 --- a/vendor/symfony/console/Resources/completion.zsh +++ b/vendor/symfony/console/Resources/completion.zsh @@ -1,3 +1,5 @@ +#compdef {{ COMMAND_NAME }} + # This file is part of the Symfony package. # # (c) Fabien Potencier diff --git a/vendor/symfony/console/Terminal.php b/vendor/symfony/console/Terminal.php index 216c609f..855f4114 100644 --- a/vendor/symfony/console/Terminal.php +++ b/vendor/symfony/console/Terminal.php @@ -123,20 +123,19 @@ class Terminal return self::$stty; } - // skip check if exec function is disabled - if (!\function_exists('exec')) { + // skip check if shell_exec function is disabled + if (!\function_exists('shell_exec')) { return false; } - exec('stty 2>&1', $output, $exitcode); - - return self::$stty = 0 === $exitcode; + return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } private static function initDimensions() { if ('\\' === \DIRECTORY_SEPARATOR) { - if (preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim(getenv('ANSICON')), $matches)) { + $ansicon = getenv('ANSICON'); + if (false !== $ansicon && preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim($ansicon), $matches)) { // extract [w, H] from "wxh (WxH)" // or [w, h] from "wxh" self::$width = (int) $matches[1]; @@ -216,6 +215,8 @@ class Terminal 2 => ['pipe', 'w'], ]; + $cp = \function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0; + $process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true]); if (!\is_resource($process)) { return null; @@ -226,6 +227,10 @@ class Terminal fclose($pipes[2]); proc_close($process); + if ($cp) { + sapi_windows_cp_set($cp); + } + return $info; } } diff --git a/vendor/symfony/console/composer.json b/vendor/symfony/console/composer.json index bafe5d16..6cc6166d 100644 --- a/vendor/symfony/console/composer.json +++ b/vendor/symfony/console/composer.json @@ -2,7 +2,7 @@ "name": "symfony/console", "type": "library", "description": "Eases the creation of beautiful and testable command line interfaces", - "keywords": ["console", "cli", "command line", "terminal"], + "keywords": ["console", "cli", "command-line", "terminal"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ diff --git a/vendor/symfony/filesystem/Filesystem.php b/vendor/symfony/filesystem/Filesystem.php index c7f3dd29..3b3cf7a1 100644 --- a/vendor/symfony/filesystem/Filesystem.php +++ b/vendor/symfony/filesystem/Filesystem.php @@ -161,7 +161,7 @@ class Filesystem } } elseif (is_dir($file)) { if (!$isRecursive) { - $tmpName = \dirname(realpath($file)).'/.'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-.')); + $tmpName = \dirname(realpath($file)).'/.'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-_')); if (file_exists($tmpName)) { try { diff --git a/vendor/symfony/string/Inflector/EnglishInflector.php b/vendor/symfony/string/Inflector/EnglishInflector.php index 4474736a..2871e4e5 100644 --- a/vendor/symfony/string/Inflector/EnglishInflector.php +++ b/vendor/symfony/string/Inflector/EnglishInflector.php @@ -55,6 +55,9 @@ final class EnglishInflector implements InflectorInterface // indices (index), appendices (appendix), prices (price) ['seci', 4, false, true, ['ex', 'ix', 'ice']], + // codes (code) + ['sedoc', 5, false, true, 'code'], + // selfies (selfie) ['seifles', 7, true, true, 'selfie'], @@ -64,6 +67,9 @@ final class EnglishInflector implements InflectorInterface // movies (movie) ['seivom', 6, true, true, 'movie'], + // names (name) + ['seman', 5, true, false, 'name'], + // conspectuses (conspectus), prospectuses (prospectus) ['sesutcep', 8, true, true, 'pectus'], diff --git a/vendor/vimeo/psalm/composer.json b/vendor/vimeo/psalm/composer.json index ed857f9a..cfca1191 100644 --- a/vendor/vimeo/psalm/composer.json +++ b/vendor/vimeo/psalm/composer.json @@ -44,6 +44,7 @@ }, "require-dev": { "ext-curl": "*", + "amphp/phpunit-util": "^2.0", "bamarni/composer-bin-plugin": "^1.4", "brianium/paratest": "^6.9", "mockery/mockery": "^1.5", diff --git a/vendor/vimeo/psalm/config.xsd b/vendor/vimeo/psalm/config.xsd index f4302e20..4d4f377f 100644 --- a/vendor/vimeo/psalm/config.xsd +++ b/vendor/vimeo/psalm/config.xsd @@ -62,6 +62,7 @@ + @@ -249,6 +250,7 @@ + @@ -480,6 +482,7 @@ + diff --git a/vendor/vimeo/psalm/dictionaries/CallMap.php b/vendor/vimeo/psalm/dictionaries/CallMap.php index 2e1191c8..bb61ce41 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap.php @@ -418,9 +418,7 @@ return [ 'array_uintersect_assoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable', '...rest='=>'array|callable(mixed,mixed):int'], 'array_uintersect_uassoc' => ['array', 'array'=>'array', 'rest'=>'array', 'data_compare_func'=>'callable(mixed,mixed):int', 'key_compare_func'=>'callable(mixed,mixed):int'], 'array_uintersect_uassoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', 'arg5'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], -'array_unique' => ['array', 'array'=>'array', 'flags='=>'0'], -'array_unique\'1' => ['array', 'array'=>'array', 'flags='=>'1'], -'array_unique\'2' => ['array', 'array'=>'array', 'flags='=>'2|5'], +'array_unique' => ['array', 'array'=>'array', 'flags='=>'int'], 'array_unshift' => ['int', '&rw_array'=>'array', '...values='=>'mixed'], 'array_values' => ['list', 'array'=>'array'], 'array_walk' => ['bool', '&rw_array'=>'array', 'callback'=>'callable', 'arg='=>'mixed'], @@ -612,7 +610,7 @@ return [ 'CallbackFilterIterator::next' => ['void'], 'CallbackFilterIterator::rewind' => ['void'], 'CallbackFilterIterator::valid' => ['bool'], -'ceil' => ['float', 'num'=>'float'], +'ceil' => ['float', 'num'=>'float|int'], 'chdb::__construct' => ['void', 'pathname'=>'string'], 'chdb::get' => ['string', 'key'=>'string'], 'chdb_create' => ['bool', 'pathname'=>'string', 'data'=>'array'], @@ -1260,7 +1258,7 @@ return [ 'cubrid_unbuffered_query' => ['resource', 'query'=>'string', 'conn_identifier='=>''], 'cubrid_version' => ['string'], 'curl_close' => ['void', 'handle'=>'CurlHandle'], -'curl_copy_handle' => ['CurlHandle', 'handle'=>'CurlHandle'], +'curl_copy_handle' => ['CurlHandle|false', 'handle'=>'CurlHandle'], 'curl_errno' => ['int', 'handle'=>'CurlHandle'], 'curl_error' => ['string', 'handle'=>'CurlHandle'], 'curl_escape' => ['string|false', 'handle'=>'CurlHandle', 'string'=>'string'], @@ -1293,7 +1291,6 @@ return [ 'curl_unescape' => ['string|false', 'handle'=>'CurlHandle', 'string'=>'string'], 'curl_version' => ['array', 'version='=>'int'], 'CURLFile::__construct' => ['void', 'filename'=>'string', 'mime_type='=>'?string', 'posted_filename='=>'?string'], -'CURLFile::__wakeup' => ['void'], 'CURLFile::getFilename' => ['string'], 'CURLFile::getMimeType' => ['string'], 'CURLFile::getPostFilename' => ['string'], @@ -1321,7 +1318,7 @@ return [ 'date_get_last_errors' => ['array{warning_count:int,warnings:array,error_count:int,errors:array}|false'], 'date_interval_create_from_date_string' => ['DateInterval', 'datetime'=>'string'], 'date_interval_format' => ['string', 'object'=>'DateInterval', 'format'=>'string'], -'date_isodate_set' => ['DateTime|false', 'object'=>'DateTime', 'year'=>'int', 'week'=>'int', 'dayOfWeek='=>'int|mixed'], +'date_isodate_set' => ['DateTime', 'object'=>'DateTime', 'year'=>'int', 'week'=>'int', 'dayOfWeek='=>'int'], 'date_modify' => ['DateTime|false', 'object'=>'DateTime', 'modifier'=>'string'], 'date_offset_get' => ['int', 'object'=>'DateTimeInterface'], 'date_parse' => ['array', 'datetime'=>'string'], @@ -1350,7 +1347,7 @@ return [ 'datefmt_get_timezone_id' => ['string|false', 'formatter'=>'IntlDateFormatter'], 'datefmt_is_lenient' => ['bool', 'formatter'=>'IntlDateFormatter'], 'datefmt_localtime' => ['array|false', 'formatter'=>'IntlDateFormatter', 'string'=>'string', '&rw_offset='=>'int'], -'datefmt_parse' => ['int|false', 'formatter'=>'IntlDateFormatter', 'string'=>'string', '&rw_offset='=>'int'], +'datefmt_parse' => ['float|int|false', 'formatter'=>'IntlDateFormatter', 'string'=>'string', '&rw_offset='=>'int'], 'datefmt_set_calendar' => ['bool', 'formatter'=>'IntlDateFormatter', 'calendar'=>'IntlCalendar|int|null'], 'datefmt_set_lenient' => ['void', 'formatter'=>'IntlDateFormatter', 'lenient'=>'bool'], 'datefmt_set_pattern' => ['bool', 'formatter'=>'IntlDateFormatter', 'pattern'=>'string'], @@ -1463,20 +1460,20 @@ return [ 'db2_tableprivileges' => [''], 'db2_tables' => ['resource|false', 'connection'=>'resource', 'qualifier='=>'?string', 'schema='=>'?string', 'table_name='=>'?string', 'table_type='=>'?string'], 'dba_close' => ['void', 'dba'=>'resource'], -'dba_delete' => ['bool', 'key'=>'string', 'dba'=>'resource'], -'dba_exists' => ['bool', 'key'=>'string', 'dba'=>'resource'], -'dba_fetch' => ['string|false', 'key'=>'string', 'skip'=>'int', 'dba'=>'resource'], -'dba_fetch\'1' => ['string|false', 'key'=>'string', 'skip'=>'resource'], +'dba_delete' => ['bool', 'key'=>'array|string', 'dba'=>'resource'], +'dba_exists' => ['bool', 'key'=>'array|string', 'dba'=>'resource'], +'dba_fetch' => ['string|false', 'key'=>'array|string', 'skip'=>'int', 'dba'=>'resource'], +'dba_fetch\'1' => ['string|false', 'key'=>'array|string', 'skip'=>'resource'], 'dba_firstkey' => ['string', 'dba'=>'resource'], 'dba_handlers' => ['array', 'full_info='=>'bool'], -'dba_insert' => ['bool', 'key'=>'string', 'value'=>'string', 'dba'=>'resource'], +'dba_insert' => ['bool', 'key'=>'array|string', 'value'=>'string', 'dba'=>'resource'], 'dba_key_split' => ['array|false', 'key'=>'string|false|null'], 'dba_list' => ['array'], 'dba_nextkey' => ['string', 'dba'=>'resource'], 'dba_open' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'?string', 'permission='=>'int', 'map_size='=>'int', 'flags='=>'?int'], 'dba_optimize' => ['bool', 'dba'=>'resource'], 'dba_popen' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'?string', 'permission='=>'int', 'map_size='=>'int', 'flags='=>'?int'], -'dba_replace' => ['bool', 'key'=>'string', 'value'=>'string', 'dba'=>'resource'], +'dba_replace' => ['bool', 'key'=>'array|string', 'value'=>'string', 'dba'=>'resource'], 'dba_sync' => ['bool', 'dba'=>'resource'], 'dbase_add_record' => ['bool', 'dbase_identifier'=>'resource', 'record'=>'array'], 'dbase_close' => ['bool', 'dbase_identifier'=>'resource'], @@ -1990,7 +1987,7 @@ return [ 'Ds\Vector::sum' => ['int|float'], 'Ds\Vector::toArray' => ['array'], 'Ds\Vector::unshift' => ['void', '...values='=>'mixed'], -'easter_date' => ['int', 'year='=>'?int'], +'easter_date' => ['int', 'year='=>'?int', 'mode='=>'int'], 'easter_days' => ['int', 'year='=>'?int', 'mode='=>'int'], 'echo' => ['void', 'arg1'=>'string', '...args='=>'string'], 'eio_busy' => ['resource', 'delay'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], @@ -2882,7 +2879,7 @@ return [ 'finfo_set_flags' => ['bool', 'finfo'=>'finfo', 'flags'=>'int'], 'floatval' => ['float', 'value'=>'mixed'], 'flock' => ['bool', 'stream'=>'resource', 'operation'=>'int', '&w_would_block='=>'int'], -'floor' => ['float', 'num'=>'float'], +'floor' => ['float', 'num'=>'float|int'], 'flush' => ['void'], 'fmod' => ['float', 'num1'=>'float', 'num2'=>'float'], 'fnmatch' => ['bool', 'pattern'=>'string', 'filename'=>'string', 'flags='=>'int'], @@ -3159,7 +3156,6 @@ return [ 'Gender\Gender::get' => ['int', 'name'=>'string', 'country='=>'int'], 'Gender\Gender::isNick' => ['array', 'name0'=>'string', 'name1'=>'string', 'country='=>'int'], 'Gender\Gender::similarNames' => ['array', 'name'=>'string', 'country='=>'int'], -'Generator::__wakeup' => ['void'], 'Generator::current' => ['mixed'], 'Generator::getReturn' => ['mixed'], 'Generator::key' => ['mixed'], @@ -3280,8 +3276,8 @@ return [ 'get_called_class' => ['class-string'], 'get_cfg_var' => ['string|false', 'option'=>'string'], 'get_class' => ['class-string', 'object='=>'object'], -'get_class_methods' => ['list', 'object_or_class'=>'object|class-string'], -'get_class_vars' => ['array', 'class'=>'string'], +'get_class_methods' => ['list', 'object_or_class'=>'object|class-string'], +'get_class_vars' => ['array', 'class'=>'string'], 'get_current_user' => ['string'], 'get_debug_type' => ['string', 'value'=>'mixed'], 'get_declared_classes' => ['list'], @@ -3333,7 +3329,7 @@ return [ 'gettimeofday' => ['array'], 'gettimeofday\'1' => ['float', 'as_float='=>'true'], 'gettype' => ['string', 'value'=>'mixed'], -'glob' => ['list|false', 'pattern'=>'string', 'flags='=>'int'], +'glob' => ['list|false', 'pattern'=>'non-empty-string', 'flags='=>'int<1, max>'], 'GlobIterator::__construct' => ['void', 'pattern'=>'string', 'flags='=>'int'], 'GlobIterator::count' => ['int'], 'GlobIterator::current' => ['FilesystemIterator|SplFileInfo|string'], @@ -3555,9 +3551,7 @@ return [ 'GmagickPixel::setcolorvalue' => ['GmagickPixel', 'color'=>'int', 'value'=>'float'], 'gmdate' => ['string', 'format'=>'string', 'timestamp='=>'int|null'], 'gmmktime' => ['int|false', 'hour'=>'int', 'minute='=>'int|null', 'second='=>'int|null', 'month='=>'int|null', 'day='=>'int|null', 'year='=>'int|null'], -'GMP::__construct' => ['void'], 'GMP::__serialize' => ['array'], -'GMP::__toString' => ['numeric-string'], 'GMP::__unserialize' => ['void', 'data'=>'array'], 'gmp_abs' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_add' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], @@ -3742,19 +3736,19 @@ return [ 'gzdeflate' => ['string|false', 'data'=>'string', 'level='=>'int', 'encoding='=>'int'], 'gzencode' => ['string|false', 'data'=>'string', 'level='=>'int', 'encoding='=>'int'], 'gzeof' => ['bool', 'stream'=>'resource'], -'gzfile' => ['list', 'filename'=>'string', 'use_include_path='=>'int'], +'gzfile' => ['list|false', 'filename'=>'string', 'use_include_path='=>'int'], 'gzgetc' => ['string|false', 'stream'=>'resource'], 'gzgets' => ['string|false', 'stream'=>'resource', 'length='=>'?int'], 'gzinflate' => ['string|false', 'data'=>'string', 'max_length='=>'int'], 'gzopen' => ['resource|false', 'filename'=>'string', 'mode'=>'string', 'use_include_path='=>'int'], 'gzpassthru' => ['int', 'stream'=>'resource'], -'gzputs' => ['int', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], +'gzputs' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], 'gzread' => ['string|false', 'stream'=>'resource', 'length'=>'int'], 'gzrewind' => ['bool', 'stream'=>'resource'], 'gzseek' => ['int', 'stream'=>'resource', 'offset'=>'int', 'whence='=>'int'], 'gztell' => ['int|false', 'stream'=>'resource'], 'gzuncompress' => ['string|false', 'data'=>'string', 'max_length='=>'int'], -'gzwrite' => ['int', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], +'gzwrite' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], 'HaruAnnotation::setBorderStyle' => ['bool', 'width'=>'float', 'dash_on'=>'int', 'dash_off'=>'int'], 'HaruAnnotation::setHighlightMode' => ['bool', 'mode'=>'int'], 'HaruAnnotation::setIcon' => ['bool', 'icon'=>'int'], @@ -6129,10 +6123,10 @@ return [ 'Iterator::rewind' => ['void'], 'Iterator::valid' => ['bool'], 'iterator_apply' => ['0|positive-int', 'iterator'=>'Traversable', 'callback'=>'callable(mixed):bool', 'args='=>'?array'], -'iterator_count' => ['0|positive-int', 'iterator'=>'Traversable'], -'iterator_to_array' => ['array', 'iterator'=>'Traversable', 'preserve_keys='=>'bool'], +'iterator_count' => ['0|positive-int', 'iterator'=>'Traversable|array'], +'iterator_to_array' => ['array', 'iterator'=>'Traversable|array', 'preserve_keys='=>'bool'], 'IteratorAggregate::getIterator' => ['Traversable'], -'IteratorIterator::__construct' => ['void', 'it'=>'Traversable'], +'IteratorIterator::__construct' => ['void', 'iterator'=>'Traversable', 'class='=>'?string'], 'IteratorIterator::current' => ['mixed'], 'IteratorIterator::getInnerIterator' => ['Iterator'], 'IteratorIterator::key' => ['mixed'], @@ -6164,7 +6158,7 @@ return [ 'json_last_error_msg' => ['string'], 'json_validate' => ['bool', 'json'=>'string', 'depth='=>'positive-int', 'flags='=>'int'], 'JsonException::__clone' => ['void'], -'JsonException::__construct' => ['void'], +'JsonException::__construct' => ['void', "message="=>"string", 'code='=>'int', 'previous='=>'?Throwable'], 'JsonException::__toString' => ['string'], 'JsonException::__wakeup' => ['void'], 'JsonException::getCode' => ['int'], @@ -6339,7 +6333,7 @@ return [ 'ldap_count_entries' => ['int', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result'], 'ldap_delete' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'controls='=>'?array'], 'ldap_delete_ext' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'controls='=>'?array'], -'ldap_dn2ufn' => ['string', 'dn'=>'string'], +'ldap_dn2ufn' => ['string|false', 'dn'=>'string'], 'ldap_err2str' => ['string', 'errno'=>'int'], 'ldap_errno' => ['int', 'ldap'=>'LDAP\Connection'], 'ldap_error' => ['string', 'ldap'=>'LDAP\Connection'], @@ -6359,7 +6353,7 @@ return [ 'ldap_get_option' => ['bool', 'ldap'=>'LDAP\Connection', 'option'=>'int', '&w_value='=>'array|string|int'], 'ldap_get_values' => ['array|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry', 'attribute'=>'string'], 'ldap_get_values_len' => ['array|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry', 'attribute'=>'string'], -'ldap_list' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], +'ldap_list' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], 'ldap_mod_add' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_mod_add_ext' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_mod_del' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], @@ -6374,11 +6368,11 @@ return [ 'ldap_parse_exop' => ['bool', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result', '&w_response_data='=>'string', '&w_response_oid='=>'string'], 'ldap_parse_reference' => ['bool', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry', '&w_referrals'=>'array'], 'ldap_parse_result' => ['bool', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result', '&w_error_code'=>'int', '&w_matched_dn='=>'string', '&w_error_message='=>'string', '&w_referrals='=>'array', '&w_controls='=>'array'], -'ldap_read' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], +'ldap_read' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], 'ldap_rename' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], 'ldap_rename_ext' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], 'ldap_sasl_bind' => ['bool', 'ldap'=>'LDAP\Connection', 'dn='=>'?string', 'password='=>'?string', 'mech='=>'?string', 'realm='=>'?string', 'authc_id='=>'?string', 'authz_id='=>'?string', 'props='=>'?string'], -'ldap_search' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], +'ldap_search' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], 'ldap_set_option' => ['bool', 'ldap'=>'LDAP\Connection|null', 'option'=>'int', 'value'=>'mixed'], 'ldap_set_rebind_proc' => ['bool', 'ldap'=>'LDAP\Connection', 'callback'=>'?callable'], 'ldap_start_tls' => ['bool', 'ldap'=>'LDAP\Connection'], @@ -6442,14 +6436,14 @@ return [ 'libxml_set_external_entity_loader' => ['bool', 'resolver_function'=>'(callable(string,string,array{directory:?string,intSubName:?string,extSubURI:?string,extSubSystem:?string}):(resource|string|null))|null'], 'libxml_set_streams_context' => ['void', 'context'=>'resource'], 'libxml_use_internal_errors' => ['bool', 'use_errors='=>'?bool'], -'LimitIterator::__construct' => ['void', 'iterator'=>'Iterator', 'offset='=>'int', 'count='=>'int'], +'LimitIterator::__construct' => ['void', 'iterator'=>'Iterator', 'offset='=>'int', 'limit='=>'int'], 'LimitIterator::current' => ['mixed'], 'LimitIterator::getInnerIterator' => ['Iterator'], 'LimitIterator::getPosition' => ['int'], 'LimitIterator::key' => ['mixed'], 'LimitIterator::next' => ['void'], 'LimitIterator::rewind' => ['void'], -'LimitIterator::seek' => ['int', 'position'=>'int'], +'LimitIterator::seek' => ['int', 'offset'=>'int'], 'LimitIterator::valid' => ['bool'], 'lineObj::__construct' => ['void'], 'lineObj::add' => ['int', 'point'=>'pointObj'], @@ -6848,14 +6842,14 @@ return [ 'memory_reset_peak_usage' => ['void'], 'MessageFormatter::__construct' => ['void', 'locale'=>'string', 'pattern'=>'string'], 'MessageFormatter::create' => ['MessageFormatter', 'locale'=>'string', 'pattern'=>'string'], -'MessageFormatter::format' => ['false|string', 'args'=>'array'], -'MessageFormatter::formatMessage' => ['false|string', 'locale'=>'string', 'pattern'=>'string', 'args'=>'array'], +'MessageFormatter::format' => ['false|string', 'values'=>'array'], +'MessageFormatter::formatMessage' => ['false|string', 'locale'=>'string', 'pattern'=>'string', 'values'=>'array'], 'MessageFormatter::getErrorCode' => ['int'], 'MessageFormatter::getErrorMessage' => ['string'], 'MessageFormatter::getLocale' => ['string'], 'MessageFormatter::getPattern' => ['string'], -'MessageFormatter::parse' => ['array|false', 'value'=>'string'], -'MessageFormatter::parseMessage' => ['array|false', 'locale'=>'string', 'pattern'=>'string', 'source'=>'string'], +'MessageFormatter::parse' => ['array|false', 'string'=>'string'], +'MessageFormatter::parseMessage' => ['array|false', 'locale'=>'string', 'pattern'=>'string', 'message'=>'string'], 'MessageFormatter::setPattern' => ['bool', 'pattern'=>'string'], 'metaphone' => ['string', 'string'=>'string', 'max_phonemes='=>'int'], 'method_exists' => ['bool', 'object_or_class'=>'object|class-string|interface-string|enum-string', 'method'=>'string'], @@ -7065,7 +7059,7 @@ return [ 'MongoDB::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags='=>'array'], 'MongoDB::setSlaveOkay' => ['bool', 'ok='=>'bool'], 'MongoDB::setWriteConcern' => ['bool', 'w'=>'mixed', 'wtimeout='=>'int'], -'MongoDB\BSON\Binary::__construct' => ['void', 'data' => 'string', 'type' => 'int'], +'MongoDB\BSON\Binary::__construct' => ['void', 'data' => 'string', 'type=' => 'int'], 'MongoDB\BSON\Binary::getData' => ['string'], 'MongoDB\BSON\Binary::getType' => ['int'], 'MongoDB\BSON\Binary::__toString' => ['string'], @@ -7623,7 +7617,7 @@ return [ 'mt_rand\'1' => ['int'], 'mt_srand' => ['void', 'seed='=>'int', 'mode='=>'int'], 'MultipleIterator::__construct' => ['void', 'flags='=>'int'], -'MultipleIterator::attachIterator' => ['void', 'iterator'=>'Iterator', 'infos='=>'string'], +'MultipleIterator::attachIterator' => ['void', 'iterator'=>'Iterator', 'info='=>'string|int|null'], 'MultipleIterator::containsIterator' => ['bool', 'iterator'=>'Iterator'], 'MultipleIterator::countIterators' => ['int'], 'MultipleIterator::current' => ['array|false'], @@ -7811,7 +7805,6 @@ return [ 'mysqli::commit' => ['bool', 'flags='=>'int', 'name='=>'?string'], 'mysqli::connect' => ['bool', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'], 'mysqli::debug' => ['bool', 'options'=>'string'], -'mysqli::disable_reads_from_master' => ['bool'], 'mysqli::dump_debug_info' => ['bool'], 'mysqli::escape_string' => ['string', 'string'=>'string'], 'mysqli::execute_query' => ['mysqli_result|bool', 'query'=>'non-empty-string', 'params='=>'list|null'], @@ -7826,23 +7819,19 @@ return [ 'mysqli::next_result' => ['bool'], 'mysqli::options' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'mysqli::ping' => ['bool'], -'mysqli::poll' => ['int|false', '&w_read'=>'array', '&w_write'=>'array', '&w_error'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], +'mysqli::poll' => ['int|false', '&w_read'=>'?array', '&w_error'=>'?array', '&w_reject'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], 'mysqli::prepare' => ['mysqli_stmt|false', 'query'=>'string'], 'mysqli::query' => ['bool|mysqli_result', 'query'=>'string', 'result_mode='=>'int'], -'mysqli::real_connect' => ['bool', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null', 'flags='=>'int'], +'mysqli::real_connect' => ['bool', 'hostname='=>'?string', 'username='=>'?string', 'password='=>'?string', 'database='=>'?string', 'port='=>'?int', 'socket='=>'?string', 'flags='=>'int'], 'mysqli::real_escape_string' => ['string', 'string'=>'string'], 'mysqli::real_query' => ['bool', 'query'=>'string'], 'mysqli::reap_async_query' => ['mysqli_result|false'], 'mysqli::refresh' => ['bool', 'flags'=>'int'], 'mysqli::release_savepoint' => ['bool', 'name'=>'string'], 'mysqli::rollback' => ['bool', 'flags='=>'int', 'name='=>'?string'], -'mysqli::rpl_query_type' => ['int', 'query'=>'string'], 'mysqli::savepoint' => ['bool', 'name'=>'string'], 'mysqli::select_db' => ['bool', 'database'=>'string'], -'mysqli::send_query' => ['bool', 'query'=>'string'], 'mysqli::set_charset' => ['bool', 'charset'=>'string'], -'mysqli::set_local_infile_default' => ['void'], -'mysqli::set_local_infile_handler' => ['bool', 'read_func='=>'callable'], 'mysqli::set_opt' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'mysqli::ssl_set' => ['bool', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'], 'mysqli::stat' => ['string|false'], @@ -7864,8 +7853,6 @@ return [ 'mysqli_debug' => ['true', 'options'=>'string'], 'mysqli_disable_reads_from_master' => ['bool', 'link'=>'mysqli'], 'mysqli_disable_rpl_parse' => ['bool', 'link'=>'mysqli'], -'mysqli_driver::embedded_server_end' => ['void'], -'mysqli_driver::embedded_server_start' => ['bool', 'start'=>'int', 'arguments'=>'array', 'groups'=>'array'], 'mysqli_dump_debug_info' => ['bool', 'mysql'=>'mysqli'], 'mysqli_embedded_server_end' => ['void'], 'mysqli_embedded_server_start' => ['bool', 'start'=>'int', 'arguments'=>'array', 'groups'=>'array'], @@ -7885,9 +7872,9 @@ return [ 'mysqli_fetch_array\'2' => ['list|false|null', 'result'=>'mysqli_result', 'mode='=>'2'], 'mysqli_fetch_assoc' => ['array|false|null', 'result'=>'mysqli_result'], 'mysqli_fetch_column' => ['null|int|float|string|false', 'result'=>'mysqli_result', 'column='=>'int'], -'mysqli_fetch_field' => ['object|false', 'result'=>'mysqli_result'], -'mysqli_fetch_field_direct' => ['object|false', 'result'=>'mysqli_result', 'index'=>'int'], -'mysqli_fetch_fields' => ['stdClass[]', 'result'=>'mysqli_result'], +'mysqli_fetch_field' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'result'=>'mysqli_result'], +'mysqli_fetch_field_direct' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'result'=>'mysqli_result', 'index'=>'int'], +'mysqli_fetch_fields' => ['list', 'result'=>'mysqli_result'], 'mysqli_fetch_lengths' => ['array|false', 'result'=>'mysqli_result'], 'mysqli_fetch_object' => ['object|false|null', 'result'=>'mysqli_result', 'class='=>'string', 'constructor_args='=>'array'], 'mysqli_fetch_row' => ['list|false|null', 'result'=>'mysqli_result'], @@ -7920,10 +7907,10 @@ return [ 'mysqli_num_rows' => ['int<0, max>|numeric-string', 'result'=>'mysqli_result'], 'mysqli_options' => ['bool', 'mysql'=>'mysqli', 'option'=>'int', 'value'=>'string|int'], 'mysqli_ping' => ['bool', 'mysql'=>'mysqli'], -'mysqli_poll' => ['int|false', 'read'=>'array', 'write'=>'array', 'error'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], +'mysqli_poll' => ['int|false', '&w_read'=>'?array', '&w_error'=>'?array', '&w_reject'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], 'mysqli_prepare' => ['mysqli_stmt|false', 'mysql'=>'mysqli', 'query'=>'string'], 'mysqli_query' => ['mysqli_result|bool', 'mysql'=>'mysqli', 'query'=>'string', 'result_mode='=>'int'], -'mysqli_real_connect' => ['bool', 'mysql='=>'mysqli', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null', 'flags='=>'int'], +'mysqli_real_connect' => ['bool', 'mysql'=>'mysqli', 'hostname='=>'?string', 'username='=>'?string', 'password='=>'?string', 'database='=>'?string', 'port='=>'?int', 'socket='=>'?string', 'flags='=>'int'], 'mysqli_real_escape_string' => ['string', 'mysql'=>'mysqli', 'string'=>'string'], 'mysqli_real_query' => ['bool', 'mysql'=>'mysqli', 'query'=>'string'], 'mysqli_reap_async_query' => ['mysqli_result|false', 'mysql'=>'mysqli'], @@ -7941,9 +7928,9 @@ return [ 'mysqli_result::fetch_array\'2' => ['list|false|null', 'mode='=>'2'], 'mysqli_result::fetch_assoc' => ['array|false|null'], 'mysqli_result::fetch_column' => ['null|int|float|string|false', 'column='=>'int'], -'mysqli_result::fetch_field' => ['object|false'], -'mysqli_result::fetch_field_direct' => ['object|false', 'index'=>'int'], -'mysqli_result::fetch_fields' => ['stdClass[]'], +'mysqli_result::fetch_field' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false'], +'mysqli_result::fetch_field_direct' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'index'=>'int'], +'mysqli_result::fetch_fields' => ['list'], 'mysqli_result::fetch_object' => ['object|false|null', 'class='=>'string', 'constructor_args='=>'array'], 'mysqli_result::fetch_row' => ['list|false|null'], 'mysqli_result::field_seek' => ['bool', 'index'=>'int'], @@ -7965,10 +7952,10 @@ return [ 'mysqli_sqlstate' => ['string', 'mysql'=>'mysqli'], 'mysqli_ssl_set' => ['true', 'mysql'=>'mysqli', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'], 'mysqli_stat' => ['string|false', 'mysql'=>'mysqli'], -'mysqli_stmt::__construct' => ['void', 'mysql'=>'mysqli', 'query'=>'string'], +'mysqli_stmt::__construct' => ['void', 'mysql'=>'mysqli', 'query='=>'?string'], 'mysqli_stmt::attr_get' => ['int', 'attribute'=>'int'], 'mysqli_stmt::attr_set' => ['bool', 'attribute'=>'int', 'value'=>'int'], -'mysqli_stmt::bind_param' => ['bool', 'types'=>'string', '&vars'=>'mixed', '&...args='=>'mixed'], +'mysqli_stmt::bind_param' => ['bool', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'], 'mysqli_stmt::bind_result' => ['bool', '&w_var1'=>'', '&...w_vars='=>''], 'mysqli_stmt::close' => ['bool'], 'mysqli_stmt::data_seek' => ['void', 'offset'=>'int'], @@ -7988,7 +7975,7 @@ return [ 'mysqli_stmt_affected_rows' => ['int<-1, max>|numeric-string', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_attr_get' => ['int', 'statement'=>'mysqli_stmt', 'attribute'=>'int'], 'mysqli_stmt_attr_set' => ['bool', 'statement'=>'mysqli_stmt', 'attribute'=>'int', 'value'=>'int'], -'mysqli_stmt_bind_param' => ['bool', 'statement'=>'mysqli_stmt', 'types'=>'string', '&vars'=>'mixed', '&...args='=>'mixed'], +'mysqli_stmt_bind_param' => ['bool', 'statement'=>'mysqli_stmt', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'], 'mysqli_stmt_bind_result' => ['bool', 'statement'=>'mysqli_stmt', '&w_var1'=>'', '&...w_vars='=>''], 'mysqli_stmt_close' => ['true', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_data_seek' => ['void', 'statement'=>'mysqli_stmt', 'offset'=>'int'], @@ -8163,28 +8150,28 @@ return [ 'nsapi_response_headers' => ['array'], 'nsapi_virtual' => ['bool', 'uri'=>'string'], 'nthmac' => ['string', 'clent'=>'string', 'data'=>'string'], -'number_format' => ['string', 'num'=>'float|int', 'decimals='=>'int', 'decimal_separator='=>'?string', 'thousands_separator='=>'?string'], +'number_format' => ['string', 'num'=>'float', 'decimals='=>'int', 'decimal_separator='=>'?string', 'thousands_separator='=>'?string'], 'NumberFormatter::__construct' => ['void', 'locale'=>'string', 'style'=>'int', 'pattern='=>'?string'], 'NumberFormatter::create' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'?string'], 'NumberFormatter::format' => ['string|false', 'num'=>'', 'type='=>'int'], -'NumberFormatter::formatCurrency' => ['string|false', 'num'=>'float', 'currency'=>'string'], -'NumberFormatter::getAttribute' => ['int|false', 'attr'=>'int'], +'NumberFormatter::formatCurrency' => ['string|false', 'amount'=>'float', 'currency'=>'string'], +'NumberFormatter::getAttribute' => ['int|float|false', 'attribute'=>'int'], 'NumberFormatter::getErrorCode' => ['int'], 'NumberFormatter::getErrorMessage' => ['string'], 'NumberFormatter::getLocale' => ['string', 'type='=>'int'], 'NumberFormatter::getPattern' => ['string|false'], -'NumberFormatter::getSymbol' => ['string|false', 'attr'=>'int'], -'NumberFormatter::getTextAttribute' => ['string|false', 'attr'=>'int'], -'NumberFormatter::parse' => ['float|false', 'string'=>'string', 'type='=>'int', '&rw_position='=>'int'], -'NumberFormatter::parseCurrency' => ['float|false', 'string'=>'string', '&w_currency'=>'string', '&rw_position='=>'int'], -'NumberFormatter::setAttribute' => ['bool', 'attr'=>'int', 'value'=>''], +'NumberFormatter::getSymbol' => ['string|false', 'symbol'=>'int'], +'NumberFormatter::getTextAttribute' => ['string|false', 'attribute'=>'int'], +'NumberFormatter::parse' => ['int|float|false', 'string'=>'string', 'type='=>'int', '&rw_offset='=>'int'], +'NumberFormatter::parseCurrency' => ['float|false', 'string'=>'string', '&w_currency'=>'string', '&rw_offset='=>'int'], +'NumberFormatter::setAttribute' => ['bool', 'attribute'=>'int', 'value'=>'int|float'], 'NumberFormatter::setPattern' => ['bool', 'pattern'=>'string'], -'NumberFormatter::setSymbol' => ['bool', 'attr'=>'int', 'symbol'=>'string'], -'NumberFormatter::setTextAttribute' => ['bool', 'attr'=>'int', 'value'=>'string'], +'NumberFormatter::setSymbol' => ['bool', 'symbol'=>'int', 'value'=>'string'], +'NumberFormatter::setTextAttribute' => ['bool', 'attribute'=>'int', 'value'=>'string'], 'numfmt_create' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'?string'], 'numfmt_format' => ['string|false', 'formatter'=>'NumberFormatter', 'num'=>'int|float', 'type='=>'int'], 'numfmt_format_currency' => ['string|false', 'formatter'=>'NumberFormatter', 'amount'=>'float', 'currency'=>'string'], -'numfmt_get_attribute' => ['int|false', 'formatter'=>'NumberFormatter', 'attribute'=>'int'], +'numfmt_get_attribute' => ['float|int|false', 'formatter'=>'NumberFormatter', 'attribute'=>'int'], 'numfmt_get_error_code' => ['int', 'formatter'=>'NumberFormatter'], 'numfmt_get_error_message' => ['string', 'formatter'=>'NumberFormatter'], 'numfmt_get_locale' => ['string', 'formatter'=>'NumberFormatter', 'type='=>'int'], @@ -8193,7 +8180,7 @@ return [ 'numfmt_get_text_attribute' => ['string|false', 'formatter'=>'NumberFormatter', 'attribute'=>'int'], 'numfmt_parse' => ['float|int|false', 'formatter'=>'NumberFormatter', 'string'=>'string', 'type='=>'int', '&rw_offset='=>'int'], 'numfmt_parse_currency' => ['float|false', 'formatter'=>'NumberFormatter', 'string'=>'string', '&w_currency'=>'string', '&rw_offset='=>'int'], -'numfmt_set_attribute' => ['bool', 'formatter'=>'NumberFormatter', 'attribute'=>'int', 'value'=>'int'], +'numfmt_set_attribute' => ['bool', 'formatter'=>'NumberFormatter', 'attribute'=>'int', 'value'=>'float|int'], 'numfmt_set_pattern' => ['bool', 'formatter'=>'NumberFormatter', 'pattern'=>'string'], 'numfmt_set_symbol' => ['bool', 'formatter'=>'NumberFormatter', 'symbol'=>'int', 'value'=>'string'], 'numfmt_set_text_attribute' => ['bool', 'formatter'=>'NumberFormatter', 'attribute'=>'int', 'value'=>'string'], @@ -8408,9 +8395,9 @@ return [ 'odbc_pconnect' => ['resource|false', 'dsn'=>'string', 'user'=>'string', 'password'=>'string', 'cursor_option='=>'int'], 'odbc_prepare' => ['resource|false', 'odbc'=>'resource', 'query'=>'string'], 'odbc_primarykeys' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string'], -'odbc_procedurecolumns' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'string', 'schema'=>'string', 'procedure'=>'string', 'column'=>'string'], -'odbc_procedures' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'string', 'schema'=>'string', 'procedure'=>'string'], -'odbc_result' => ['mixed|false', 'statement'=>'resource', 'field'=>'mixed'], +'odbc_procedurecolumns' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'procedure='=>'?string', 'column='=>'?string'], +'odbc_procedures' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'procedure='=>'?string'], +'odbc_result' => ['string|bool|null', 'statement'=>'resource', 'field'=>'string|int'], 'odbc_result_all' => ['int|false', 'statement'=>'resource', 'format='=>'string'], 'odbc_rollback' => ['bool', 'odbc'=>'resource'], 'odbc_setoption' => ['bool', 'odbc'=>'resource', 'which'=>'int', 'option'=>'int', 'value'=>'int'], @@ -8476,7 +8463,7 @@ return [ 'openssl_pkcs12_read' => ['bool', 'pkcs12'=>'string', '&w_certificates'=>'array', 'passphrase'=>'string'], 'openssl_pkcs7_decrypt' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'OpenSSLCertificate|string', 'private_key='=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string|null'], 'openssl_pkcs7_encrypt' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'OpenSSLCertificate|list|string', 'headers'=>'array|null', 'flags='=>'int', 'cipher_algo='=>'int'], -'openssl_pkcs7_read' => ['bool', 'input_filename'=>'string', '&w_certificates'=>'array'], +'openssl_pkcs7_read' => ['bool', 'data'=>'string', '&w_certificates'=>'array'], 'openssl_pkcs7_sign' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'OpenSSLCertificate|string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'headers'=>'array|null', 'flags='=>'int', 'untrusted_certificates_filename='=>'string|null'], 'openssl_pkcs7_verify' => ['bool|int', 'input_filename'=>'string', 'flags'=>'int', 'signers_certificates_filename='=>'?string', 'ca_info='=>'array', 'untrusted_certificates_filename='=>'?string', 'content='=>'?string', 'output_filename='=>'?string'], 'openssl_pkey_derive' => ['string|false', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'key_length='=>'int'], @@ -8998,8 +8985,6 @@ return [ 'PDFlib::utf32_to_utf16' => ['string', 'utf32string'=>'string', 'ordering'=>'string'], 'PDFlib::utf8_to_utf16' => ['string', 'utf8string'=>'string', 'ordering'=>'string'], 'PDO::__construct' => ['void', 'dsn'=>'string', 'username='=>'?string', 'password='=>'?string', 'options='=>'?array'], -'PDO::__sleep' => ['list'], -'PDO::__wakeup' => ['void'], 'PDO::beginTransaction' => ['bool'], 'PDO::commit' => ['bool'], 'PDO::cubrid_schema' => ['array', 'schema_type'=>'int', 'table_name='=>'string', 'col_name='=>'string'], @@ -9038,8 +9023,6 @@ return [ 'PDOException::getPrevious' => ['?Throwable'], 'PDOException::getTrace' => ['list\',args?:array}>'], 'PDOException::getTraceAsString' => ['string'], -'PDOStatement::__sleep' => ['list'], -'PDOStatement::__wakeup' => ['void'], 'PDOStatement::bindColumn' => ['bool', 'column'=>'string|int', '&rw_var'=>'mixed', 'type='=>'int', 'maxLength='=>'int', 'driverOptions='=>'mixed'], 'PDOStatement::bindParam' => ['bool', 'param'=>'string|int', '&rw_var'=>'mixed', 'type='=>'int', 'maxLength='=>'int', 'driverOptions='=>'mixed'], 'PDOStatement::bindValue' => ['bool', 'param'=>'string|int', 'value'=>'mixed', 'type='=>'int'], @@ -9640,7 +9623,7 @@ return [ 'rand\'1' => ['int'], 'random_bytes' => ['non-empty-string', 'length'=>'positive-int'], 'random_int' => ['int', 'min'=>'int', 'max'=>'int'], -'range' => ['array', 'start'=>'mixed', 'end'=>'mixed', 'step='=>'int|float'], +'range' => ['non-empty-array', 'start'=>'string|int|float', 'end'=>'string|int|float', 'step='=>'int<1, max>|float'], 'RangeException::__clone' => ['void'], 'RangeException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'RangeException::__toString' => ['string'], @@ -10443,7 +10426,7 @@ return [ 'RedisCluster::zUnionStore' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'Reflection::getModifierNames' => ['list', 'modifiers'=>'int'], 'ReflectionClass::__clone' => ['void'], -'ReflectionClass::__construct' => ['void', 'argument'=>'object|class-string'], +'ReflectionClass::__construct' => ['void', 'objectOrClass'=>'object|class-string'], 'ReflectionClass::__toString' => ['string'], 'ReflectionClass::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionClass::getConstant' => ['mixed', 'name'=>'string'], @@ -10477,7 +10460,7 @@ return [ 'ReflectionClass::hasConstant' => ['bool', 'name'=>'string'], 'ReflectionClass::hasMethod' => ['bool', 'name'=>'string'], 'ReflectionClass::hasProperty' => ['bool', 'name'=>'string'], -'ReflectionClass::implementsInterface' => ['bool', 'interface_name'=>'interface-string|ReflectionClass'], +'ReflectionClass::implementsInterface' => ['bool', 'interface'=>'interface-string|ReflectionClass'], 'ReflectionClass::inNamespace' => ['bool'], 'ReflectionClass::isAbstract' => ['bool'], 'ReflectionClass::isAnonymous' => ['bool'], @@ -10497,7 +10480,7 @@ return [ 'ReflectionClass::newInstanceArgs' => ['object', 'args='=>'list|array'], 'ReflectionClass::newInstanceWithoutConstructor' => ['object'], 'ReflectionClass::setStaticPropertyValue' => ['void', 'name'=>'string', 'value'=>'mixed'], -'ReflectionClassConstant::__construct' => ['void', 'class'=>'mixed', 'name'=>'string'], +'ReflectionClassConstant::__construct' => ['void', 'class'=>'object|class-string', 'constant'=>'string'], 'ReflectionClassConstant::__toString' => ['string'], 'ReflectionClassConstant::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionClassConstant::getDeclaringClass' => ['ReflectionClass'], @@ -10530,7 +10513,7 @@ return [ 'ReflectionExtension::info' => ['void'], 'ReflectionExtension::isPersistent' => ['bool'], 'ReflectionExtension::isTemporary' => ['bool'], -'ReflectionFunction::__construct' => ['void', 'name'=>'callable-string|Closure'], +'ReflectionFunction::__construct' => ['void', 'function'=>'callable-string|Closure'], 'ReflectionFunction::__toString' => ['string'], 'ReflectionFunction::getClosure' => ['Closure'], 'ReflectionFunction::getClosureScopeClass' => ['ReflectionClass'], @@ -10592,7 +10575,7 @@ return [ 'ReflectionFunctionAbstract::isUserDefined' => ['bool'], 'ReflectionFunctionAbstract::isVariadic' => ['bool'], 'ReflectionFunctionAbstract::returnsReference' => ['bool'], -'ReflectionGenerator::__construct' => ['void', 'generator'=>'object'], +'ReflectionGenerator::__construct' => ['void', 'generator'=>'Generator'], 'ReflectionGenerator::getExecutingFile' => ['string'], 'ReflectionGenerator::getExecutingGenerator' => ['Generator'], 'ReflectionGenerator::getExecutingLine' => ['int'], @@ -10640,17 +10623,17 @@ return [ 'ReflectionMethod::isUserDefined' => ['bool'], 'ReflectionMethod::isVariadic' => ['bool'], 'ReflectionMethod::returnsReference' => ['bool'], -'ReflectionMethod::setAccessible' => ['void', 'visible'=>'bool'], +'ReflectionMethod::setAccessible' => ['void', 'accessible'=>'bool'], 'ReflectionNamedType::__clone' => ['void'], 'ReflectionNamedType::__toString' => ['string'], 'ReflectionNamedType::allowsNull' => ['bool'], 'ReflectionNamedType::getName' => ['string'], 'ReflectionNamedType::isBuiltin' => ['bool'], 'ReflectionObject::__clone' => ['void'], -'ReflectionObject::__construct' => ['void', 'argument'=>'object'], +'ReflectionObject::__construct' => ['void', 'object'=>'object'], 'ReflectionObject::__toString' => ['string'], 'ReflectionObject::getConstant' => ['mixed', 'name'=>'string'], -'ReflectionObject::getConstants' => ['array'], +'ReflectionObject::getConstants' => ['array', 'filter='=>'?int'], 'ReflectionObject::getConstructor' => ['?ReflectionMethod'], 'ReflectionObject::getDefaultProperties' => ['array'], 'ReflectionObject::getDocComment' => ['false|string'], @@ -10669,7 +10652,7 @@ return [ 'ReflectionObject::getProperties' => ['ReflectionProperty[]', 'filter='=>'?int'], 'ReflectionObject::getProperty' => ['ReflectionProperty', 'name'=>'string'], 'ReflectionObject::getReflectionConstant' => ['ReflectionClassConstant', 'name'=>'string'], -'ReflectionObject::getReflectionConstants' => ['list<\ReflectionClassConstant>'], +'ReflectionObject::getReflectionConstants' => ['list<\ReflectionClassConstant>', 'filter='=>'?int'], 'ReflectionObject::getShortName' => ['string'], 'ReflectionObject::getStartLine' => ['false|int'], 'ReflectionObject::getStaticProperties' => ['ReflectionProperty[]'], @@ -10680,7 +10663,7 @@ return [ 'ReflectionObject::hasConstant' => ['bool', 'name'=>'string'], 'ReflectionObject::hasMethod' => ['bool', 'name'=>'string'], 'ReflectionObject::hasProperty' => ['bool', 'name'=>'string'], -'ReflectionObject::implementsInterface' => ['bool', 'interface_name'=>'ReflectionClass|string'], +'ReflectionObject::implementsInterface' => ['bool', 'interface'=>'ReflectionClass|interface-string'], 'ReflectionObject::inNamespace' => ['bool'], 'ReflectionObject::isAbstract' => ['bool'], 'ReflectionObject::isAnonymous' => ['bool'], @@ -10701,7 +10684,7 @@ return [ 'ReflectionObject::newInstanceWithoutConstructor' => ['object'], 'ReflectionObject::setStaticPropertyValue' => ['void', 'name'=>'string', 'value'=>'string'], 'ReflectionParameter::__clone' => ['void'], -'ReflectionParameter::__construct' => ['void', 'function'=>'', 'parameter'=>''], +'ReflectionParameter::__construct' => ['void', 'function'=>'string|array|object', 'param'=>'int|string'], 'ReflectionParameter::__toString' => ['string'], 'ReflectionParameter::allowsNull' => ['bool'], 'ReflectionParameter::canBePassedByValue' => ['bool'], @@ -10723,7 +10706,7 @@ return [ 'ReflectionParameter::isPassedByReference' => ['bool'], 'ReflectionParameter::isVariadic' => ['bool'], 'ReflectionProperty::__clone' => ['void'], -'ReflectionProperty::__construct' => ['void', 'class'=>'', 'name'=>'string'], +'ReflectionProperty::__construct' => ['void', 'class'=>'object|class-string', 'property'=>'string'], 'ReflectionProperty::__toString' => ['string'], 'ReflectionProperty::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionProperty::getDeclaringClass' => ['ReflectionClass'], @@ -10738,7 +10721,7 @@ return [ 'ReflectionProperty::isProtected' => ['bool'], 'ReflectionProperty::isPublic' => ['bool'], 'ReflectionProperty::isStatic' => ['bool'], -'ReflectionProperty::setAccessible' => ['void', 'visible'=>'bool'], +'ReflectionProperty::setAccessible' => ['void', 'accessible'=>'bool'], 'ReflectionProperty::setValue' => ['void', 'object'=>'null|object', 'value'=>''], 'ReflectionProperty::setValue\'1' => ['void', 'value'=>''], 'ReflectionType::__clone' => ['void'], @@ -10776,13 +10759,13 @@ return [ 'rename' => ['bool', 'from'=>'string', 'to'=>'string', 'context='=>'resource'], 'rename_function' => ['bool', 'original_name'=>'string', 'new_name'=>'string'], 'reset' => ['mixed|false', '&r_array'=>'array|object'], -'ResourceBundle::__construct' => ['void', 'locale'=>'string', 'bundlename'=>'string', 'fallback='=>'bool'], +'ResourceBundle::__construct' => ['void', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'ResourceBundle::count' => ['int'], -'ResourceBundle::create' => ['?ResourceBundle', 'locale'=>'string', 'bundlename'=>'string', 'fallback='=>'bool'], +'ResourceBundle::create' => ['?ResourceBundle', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'ResourceBundle::get' => ['mixed', 'index'=>'string|int', 'fallback='=>'bool'], 'ResourceBundle::getErrorCode' => ['int'], 'ResourceBundle::getErrorMessage' => ['string'], -'ResourceBundle::getLocales' => ['array', 'bundlename'=>'string'], +'ResourceBundle::getLocales' => ['array|false', 'bundle'=>'string'], 'resourcebundle_count' => ['int', 'bundle'=>'ResourceBundle'], 'resourcebundle_create' => ['?ResourceBundle', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'resourcebundle_get' => ['mixed|null', 'bundle'=>'ResourceBundle', 'index'=>'string|int', 'fallback='=>'bool'], @@ -10795,7 +10778,7 @@ return [ 'rewind' => ['bool', 'stream'=>'resource'], 'rewinddir' => ['void', 'dir_handle='=>'resource'], 'rmdir' => ['bool', 'directory'=>'string', 'context='=>'resource'], -'round' => ['float', 'num'=>'float', 'precision='=>'int', 'mode='=>'0|positive-int'], +'round' => ['float', 'num'=>'float|int', 'precision='=>'int', 'mode='=>'0|positive-int'], 'rpm_close' => ['bool', 'rpmr'=>'resource'], 'rpm_get_tag' => ['mixed', 'rpmr'=>'resource', 'tagnum'=>'int'], 'rpm_is_valid' => ['bool', 'filename'=>'string'], @@ -11169,18 +11152,18 @@ return [ 'ServerResponse::setStatus' => ['void', 'status'=>'int'], 'ServerResponse::setVersion' => ['void', 'version'=>'string'], 'session_abort' => ['bool'], -'session_cache_expire' => ['int', 'value='=>'?int'], -'session_cache_limiter' => ['string', 'value='=>'?string'], +'session_cache_expire' => ['int|false', 'value='=>'?int'], +'session_cache_limiter' => ['string|false', 'value='=>'?string'], 'session_commit' => ['bool'], -'session_create_id' => ['string', 'prefix='=>'string'], +'session_create_id' => ['string|false', 'prefix='=>'string'], 'session_decode' => ['bool', 'data'=>'string'], 'session_destroy' => ['bool'], -'session_encode' => ['string'], +'session_encode' => ['string|false'], 'session_gc' => ['int|false'], 'session_get_cookie_params' => ['array'], 'session_id' => ['string|false', 'id='=>'?string'], 'session_is_registered' => ['bool', 'name'=>'string'], -'session_module_name' => ['string', 'module='=>'?string'], +'session_module_name' => ['string|false', 'module='=>'?string'], 'session_name' => ['string|false', 'name='=>'?string'], 'session_pgsql_add_error' => ['bool', 'error_level'=>'int', 'error_message='=>'string'], 'session_pgsql_get_error' => ['array', 'with_error_message='=>'bool'], @@ -11192,7 +11175,7 @@ return [ 'session_register' => ['bool', 'name'=>'mixed', '...args='=>'mixed'], 'session_register_shutdown' => ['void'], 'session_reset' => ['bool'], -'session_save_path' => ['string', 'path='=>'?string'], +'session_save_path' => ['string|false', 'path='=>'?string'], 'session_set_cookie_params' => ['bool', 'lifetime'=>'int', 'path='=>'?string', 'domain='=>'?string', 'secure='=>'?bool', 'httponly='=>'?bool'], 'session_set_cookie_params\'1' => ['bool', 'options'=>'array{lifetime?:?int,path?:?string,domain?:?string,secure?:?bool,httponly?:?bool,samesite?:?string}'], 'session_set_save_handler' => ['bool', 'open'=>'callable(string,string):bool', 'close'=>'callable():bool', 'read'=>'callable(string):string', 'write'=>'callable(string,string):bool', 'destroy'=>'callable(string):bool', 'gc'=>'callable(string):bool', 'create_sid='=>'callable():string', 'validate_sid='=>'callable(string):bool', 'update_timestamp='=>'callable(string):bool'], @@ -11205,9 +11188,9 @@ return [ 'SessionHandler::close' => ['bool'], 'SessionHandler::create_sid' => ['string'], 'SessionHandler::destroy' => ['bool', 'id'=>'string'], -'SessionHandler::gc' => ['bool', 'maxlifetime'=>'int'], -'SessionHandler::open' => ['bool', 'save_path'=>'string', 'session_name'=>'string'], -'SessionHandler::read' => ['string', 'id'=>'string'], +'SessionHandler::gc' => ['int|false', 'max_lifetime'=>'int'], +'SessionHandler::open' => ['bool', 'path'=>'string', 'name'=>'string'], +'SessionHandler::read' => ['string|false', 'id'=>'string'], 'SessionHandler::write' => ['bool', 'id'=>'string', 'data'=>'string'], 'SessionHandlerInterface::close' => ['bool'], 'SessionHandlerInterface::destroy' => ['bool', 'id'=>'string'], @@ -11305,40 +11288,40 @@ return [ 'simplexml_import_dom' => ['?SimpleXMLElement', 'node'=>'DOMNode', 'class_name='=>'?string'], 'simplexml_load_file' => ['SimpleXMLElement|false', 'filename'=>'string', 'class_name='=>'?string', 'options='=>'int', 'namespace_or_prefix='=>'string', 'is_prefix='=>'bool'], 'simplexml_load_string' => ['SimpleXMLElement|false', 'data'=>'string', 'class_name='=>'?string', 'options='=>'int', 'namespace_or_prefix='=>'string', 'is_prefix='=>'bool'], -'SimpleXMLElement::__construct' => ['void', 'data'=>'string', 'options='=>'int', 'data_is_url='=>'bool', 'ns='=>'string', 'is_prefix='=>'bool'], +'SimpleXMLElement::__construct' => ['void', 'data'=>'string', 'options='=>'int', 'dataIsURL='=>'bool', 'namespaceOrPrefix='=>'string', 'isPrefix='=>'bool'], 'SimpleXMLElement::__get' => ['SimpleXMLElement', 'name'=>'string'], 'SimpleXMLElement::__toString' => ['string'], -'SimpleXMLElement::addAttribute' => ['void', 'name'=>'string', 'value='=>'string', 'ns='=>'string'], -'SimpleXMLElement::addChild' => ['SimpleXMLElement', 'name'=>'string', 'value='=>'string', 'ns='=>'string'], +'SimpleXMLElement::addAttribute' => ['void', 'qualifiedName'=>'string', 'value'=>'string', 'namespace='=>'?string'], +'SimpleXMLElement::addChild' => ['?SimpleXMLElement', 'qualifiedName'=>'string', 'value='=>'?string', 'namespace='=>'?string'], 'SimpleXMLElement::asXML' => ['string|bool', 'filename='=>'?string'], 'SimpleXMLElement::asXML\'1' => ['string|false'], -'SimpleXMLElement::attributes' => ['?SimpleXMLElement', 'ns='=>'string', 'is_prefix='=>'bool'], -'SimpleXMLElement::children' => ['SimpleXMLElement', 'ns='=>'string', 'is_prefix='=>'bool'], +'SimpleXMLElement::attributes' => ['?SimpleXMLElement', 'namespaceOrPrefix='=>'?string', 'isPrefix='=>'bool'], +'SimpleXMLElement::children' => ['?SimpleXMLElement', 'namespaceOrPrefix='=>'?string', 'isPrefix='=>'bool'], 'SimpleXMLElement::count' => ['int'], -'SimpleXMLElement::getDocNamespaces' => ['string[]', 'recursive='=>'bool', 'from_root='=>'bool'], +'SimpleXMLElement::getDocNamespaces' => ['array', 'recursive='=>'bool', 'fromRoot='=>'bool'], 'SimpleXMLElement::getName' => ['string'], -'SimpleXMLElement::getNamespaces' => ['string[]', 'recursive='=>'bool'], +'SimpleXMLElement::getNamespaces' => ['array', 'recursive='=>'bool'], 'SimpleXMLElement::offsetExists' => ['bool', 'offset'=>'int|string'], 'SimpleXMLElement::offsetGet' => ['SimpleXMLElement', 'offset'=>'int|string'], 'SimpleXMLElement::offsetSet' => ['void', 'offset'=>'int|string', 'value'=>'mixed'], 'SimpleXMLElement::offsetUnset' => ['void', 'offset'=>'int|string'], -'SimpleXMLElement::registerXPathNamespace' => ['bool', 'prefix'=>'string', 'ns'=>'string'], +'SimpleXMLElement::registerXPathNamespace' => ['bool', 'prefix'=>'string', 'namespace'=>'string'], 'SimpleXMLElement::saveXML' => ['string|bool', 'filename='=>'?string'], -'SimpleXMLElement::xpath' => ['SimpleXMLElement[]|false', 'path'=>'string'], +'SimpleXMLElement::xpath' => ['SimpleXMLElement[]|false|null', 'expression'=>'string'], 'sin' => ['float', 'num'=>'float'], 'sinh' => ['float', 'num'=>'float'], 'sizeof' => ['int<0, max>', 'value'=>'Countable|array', 'mode='=>'int'], 'sleep' => ['int', 'seconds'=>'0|positive-int'], -'snmp2_get' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmp2_getnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmp2_real_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmp2_set' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'type'=>'string', 'value'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmp2_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmp3_get' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmp3_getnext' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmp3_real_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmp3_set' => ['bool', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'string', 'type'=>'string', 'value'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmp3_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], +'snmp2_get' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmp2_getnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmp2_real_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmp2_set' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'type'=>'array|string', 'value'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmp2_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmp3_get' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmp3_getnext' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmp3_real_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmp3_set' => ['bool', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'type'=>'array|string', 'value'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmp3_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'SNMP::__construct' => ['void', 'version'=>'int', 'hostname'=>'string', 'community'=>'string', 'timeout='=>'int', 'retries='=>'int'], 'SNMP::close' => ['bool'], 'SNMP::get' => ['array|string|false', 'objectId'=>'string|array', 'preserveKeys='=>'bool'], @@ -11347,7 +11330,7 @@ return [ 'SNMP::getnext' => ['string|array|false', 'objectId'=>'string|array'], 'SNMP::set' => ['bool', 'objectId'=>'string|array', 'type'=>'string|array', 'value'=>'string|array'], 'SNMP::setSecurity' => ['bool', 'securityLevel'=>'string', 'authProtocol='=>'string', 'authPassphrase='=>'string', 'privacyProtocol='=>'string', 'privacyPassphrase='=>'string', 'contextName='=>'string', 'contextEngineId='=>'string'], -'SNMP::walk' => ['array|false', 'objectId'=>'string', 'suffixAsKey='=>'bool', 'maxRepetitions='=>'int', 'nonRepeaters='=>'int'], +'SNMP::walk' => ['array|false', 'objectId'=>'array|string', 'suffixAsKey='=>'bool', 'maxRepetitions='=>'int', 'nonRepeaters='=>'int'], 'snmp_get_quick_print' => ['bool'], 'snmp_get_valueretrieval' => ['int'], 'snmp_read_mib' => ['bool', 'filename'=>'string'], @@ -11356,12 +11339,12 @@ return [ 'snmp_set_oid_output_format' => ['true', 'format'=>'int'], 'snmp_set_quick_print' => ['bool', 'enable'=>'bool'], 'snmp_set_valueretrieval' => ['true', 'method'=>'int'], -'snmpget' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmpgetnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmprealwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmpset' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'type'=>'string|string[]', 'value'=>'string|string[]', 'timeout='=>'int', 'retries='=>'int'], -'snmpwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], -'snmpwalkoid' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], +'snmpget' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmpgetnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmprealwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmpset' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'type'=>'string|string[]', 'value'=>'string|string[]', 'timeout='=>'int', 'retries='=>'int'], +'snmpwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], +'snmpwalkoid' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'SoapClient::__call' => ['', 'function_name'=>'string', 'arguments'=>'array'], 'SoapClient::__construct' => ['void', 'wsdl'=>'mixed', 'options='=>'array|null'], 'SoapClient::__doRequest' => ['?string', 'request'=>'string', 'location'=>'string', 'action'=>'string', 'version'=>'int', 'one_way='=>'bool'], @@ -11506,7 +11489,7 @@ return [ 'sodium_crypto_secretstream_xchacha20poly1305_init_pull' => ['string', 'header'=>'string', 'key'=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_init_push' => ['array', 'key'=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_keygen' => ['non-empty-string'], -'sodium_crypto_secretstream_xchacha20poly1305_pull' => ['array', '&r_state'=>'string', 'ciphertext'=>'string', 'additional_data='=>'string'], +'sodium_crypto_secretstream_xchacha20poly1305_pull' => ['array|false', '&r_state'=>'string', 'ciphertext'=>'string', 'additional_data='=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_push' => ['string', '&w_state'=>'string', 'message'=>'string', 'additional_data='=>'string', 'tag='=>'int'], 'sodium_crypto_secretstream_xchacha20poly1305_rekey' => ['void', '&w_state'=>'string'], 'sodium_crypto_shorthash' => ['string', 'message'=>'string', 'key'=>'string'], @@ -12281,10 +12264,10 @@ return [ 'SplDoublyLinkedList::isEmpty' => ['bool'], 'SplDoublyLinkedList::key' => ['int'], 'SplDoublyLinkedList::next' => ['void'], -'SplDoublyLinkedList::offsetExists' => ['bool', 'index'=>'mixed'], -'SplDoublyLinkedList::offsetGet' => ['mixed', 'index'=>'mixed'], -'SplDoublyLinkedList::offsetSet' => ['void', 'index'=>'mixed', 'value'=>'mixed'], -'SplDoublyLinkedList::offsetUnset' => ['void', 'index'=>'mixed'], +'SplDoublyLinkedList::offsetExists' => ['bool', 'index'=>'int'], +'SplDoublyLinkedList::offsetGet' => ['mixed', 'index'=>'int'], +'SplDoublyLinkedList::offsetSet' => ['void', 'index'=>'?int', 'value'=>'mixed'], +'SplDoublyLinkedList::offsetUnset' => ['void', 'index'=>'int'], 'SplDoublyLinkedList::pop' => ['mixed'], 'SplDoublyLinkedList::prev' => ['void'], 'SplDoublyLinkedList::push' => ['void', 'value'=>'mixed'], @@ -12300,7 +12283,6 @@ return [ 'SplEnum::getConstList' => ['array', 'include_default='=>'bool'], 'SplFileInfo::__construct' => ['void', 'filename'=>'string'], 'SplFileInfo::__toString' => ['string'], -'SplFileInfo::__wakeup' => ['void'], 'SplFileInfo::getATime' => ['int|false'], 'SplFileInfo::getBasename' => ['string', 'suffix='=>'string'], 'SplFileInfo::getCTime' => ['int|false'], @@ -12390,19 +12372,15 @@ return [ 'SplFixedArray::__construct' => ['void', 'size='=>'int'], 'SplFixedArray::__wakeup' => ['void'], 'SplFixedArray::count' => ['int'], -'SplFixedArray::current' => ['mixed'], 'SplFixedArray::fromArray' => ['SplFixedArray', 'array'=>'array', 'preserveKeys='=>'bool'], +'SplFixedArray::getIterator' => ['Iterator'], 'SplFixedArray::getSize' => ['int'], -'SplFixedArray::key' => ['int'], -'SplFixedArray::next' => ['void'], 'SplFixedArray::offsetExists' => ['bool', 'index'=>'int'], 'SplFixedArray::offsetGet' => ['mixed', 'index'=>'int'], 'SplFixedArray::offsetSet' => ['void', 'index'=>'int', 'value'=>'mixed'], 'SplFixedArray::offsetUnset' => ['void', 'index'=>'int'], -'SplFixedArray::rewind' => ['void'], 'SplFixedArray::setSize' => ['bool', 'size'=>'int'], 'SplFixedArray::toArray' => ['array'], -'SplFixedArray::valid' => ['bool'], 'SplHeap::__construct' => ['void'], 'SplHeap::compare' => ['int', 'value1'=>'mixed', 'value2'=>'mixed'], 'SplHeap::count' => ['int'], @@ -12586,7 +12564,7 @@ return [ 'Spoofchecker::setChecks' => ['void', 'checks'=>'int'], 'Spoofchecker::setRestrictionLevel' => ['void', 'level'=>'int'], 'sprintf' => ['string', 'format'=>'string', '...values='=>'string|int|float'], -'SQLite3::__construct' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'?string'], +'SQLite3::__construct' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'string'], 'SQLite3::busyTimeout' => ['bool', 'milliseconds'=>'int'], 'SQLite3::changes' => ['int'], 'SQLite3::close' => ['bool'], @@ -12600,7 +12578,7 @@ return [ 'SQLite3::lastErrorMsg' => ['string'], 'SQLite3::lastInsertRowID' => ['int'], 'SQLite3::loadExtension' => ['bool', 'name'=>'string'], -'SQLite3::open' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'?string'], +'SQLite3::open' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'string'], 'SQLite3::openBlob' => ['resource|false', 'table'=>'string', 'column'=>'string', 'rowid'=>'int', 'database='=>'string', 'flags='=>'int'], 'SQLite3::prepare' => ['SQLite3Stmt|false', 'query'=>'string'], 'SQLite3::query' => ['SQLite3Result|false', 'query'=>'string'], @@ -12723,7 +12701,7 @@ return [ 'sqlsrv_commit' => ['bool', 'conn'=>'resource'], 'sqlsrv_configure' => ['bool', 'setting'=>'string', 'value'=>'mixed'], 'sqlsrv_connect' => ['resource|false', 'serverName'=>'string', 'connectionInfo='=>'array'], -'sqlsrv_errors' => ['?array', 'errorsOrWarnings='=>'int'], +'sqlsrv_errors' => ['?array', 'errorsAndOrWarnings='=>'int'], 'sqlsrv_execute' => ['bool', 'stmt'=>'resource'], 'sqlsrv_fetch' => ['?bool', 'stmt'=>'resource', 'row='=>'int', 'offset='=>'int'], 'sqlsrv_fetch_array' => ['array|null|false', 'stmt'=>'resource', 'fetchType='=>'int', 'row='=>'int', 'offset='=>'int'], @@ -12898,7 +12876,7 @@ return [ 'str_replace' => ['string|string[]', 'search'=>'string|array', 'replace'=>'string|array', 'subject'=>'string|array', '&w_count='=>'int'], 'str_rot13' => ['string', 'string'=>'string'], 'str_shuffle' => ['string', 'string'=>'string'], -'str_split' => ['list', 'string'=>'string', 'length='=>'positive-int'], +'str_split' => ['list', 'string'=>'string', 'length='=>'positive-int'], 'str_starts_with' => ['bool', 'haystack'=>'string', 'needle'=>'string'], 'str_word_count' => ['array|int', 'string'=>'string', 'format='=>'int', 'characters='=>'?string'], 'strcasecmp' => ['int', 'string1'=>'string', 'string2'=>'string'], @@ -12913,7 +12891,7 @@ return [ 'stream_context_create' => ['resource', 'options='=>'?array', 'params='=>'?array'], 'stream_context_get_default' => ['resource', 'options='=>'?array'], 'stream_context_get_options' => ['array', 'stream_or_context'=>'resource'], -'stream_context_get_params' => ['array', 'context'=>'resource'], +'stream_context_get_params' => ['array{notification:string,options:array}', 'context'=>'resource'], 'stream_context_set_default' => ['resource', 'options'=>'array'], 'stream_context_set_option' => ['bool', 'context'=>'', 'wrapper_or_options'=>'string', 'option_name'=>'string', 'value'=>''], 'stream_context_set_option\'1' => ['bool', 'context'=>'', 'wrapper_or_options'=>'array'], @@ -12944,10 +12922,10 @@ return [ 'stream_socket_accept' => ['resource|false', 'socket'=>'resource', 'timeout='=>'?float', '&w_peer_name='=>'string'], 'stream_socket_client' => ['resource|false', 'address'=>'string', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'?float', 'flags='=>'int', 'context='=>'?resource'], 'stream_socket_enable_crypto' => ['int|bool', 'stream'=>'resource', 'enable'=>'bool', 'crypto_method='=>'?int', 'session_stream='=>'?resource'], -'stream_socket_get_name' => ['string', 'socket'=>'resource', 'remote'=>'bool'], +'stream_socket_get_name' => ['string|false', 'socket'=>'resource', 'remote'=>'bool'], 'stream_socket_pair' => ['resource[]|false', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int'], -'stream_socket_recvfrom' => ['string', 'socket'=>'resource', 'length'=>'int', 'flags='=>'int', '&w_address='=>'string'], -'stream_socket_sendto' => ['int', 'socket'=>'resource', 'data'=>'string', 'flags='=>'int', 'address='=>'string'], +'stream_socket_recvfrom' => ['string|false', 'socket'=>'resource', 'length'=>'int', 'flags='=>'int', '&w_address='=>'string'], +'stream_socket_sendto' => ['int|false', 'socket'=>'resource', 'data'=>'string', 'flags='=>'int', 'address='=>'string'], 'stream_socket_server' => ['resource|false', 'address'=>'string', '&w_error_code='=>'int', '&w_error_message='=>'string', 'flags='=>'int', 'context='=>'resource'], 'stream_socket_shutdown' => ['bool', 'stream'=>'resource', 'mode'=>'int'], 'stream_supports_lock' => ['bool', 'stream'=>'resource'], @@ -13603,7 +13581,7 @@ return [ 'SyncSharedMemory::size' => ['int'], 'SyncSharedMemory::write' => ['int', 'string='=>'string', 'start='=>'int'], 'sys_get_temp_dir' => ['string'], -'sys_getloadavg' => ['array'], +'sys_getloadavg' => ['array|false'], 'syslog' => ['true', 'priority'=>'int', 'message'=>'string'], 'system' => ['string|false', 'command'=>'string', '&w_result_code='=>'int'], 'taint' => ['bool', '&rw_string'=>'string', '&...w_other_strings='=>'string'], @@ -13985,7 +13963,7 @@ return [ 'Transliterator::getErrorCode' => ['int'], 'Transliterator::getErrorMessage' => ['string'], 'Transliterator::listIDs' => ['array'], -'Transliterator::transliterate' => ['string|false', 'subject'=>'string', 'start='=>'int', 'end='=>'int'], +'Transliterator::transliterate' => ['string|false', 'string'=>'string', 'start='=>'int', 'end='=>'int'], 'transliterator_create' => ['?Transliterator', 'id'=>'string', 'direction='=>'int'], 'transliterator_create_from_rules' => ['?Transliterator', 'rules'=>'string', 'direction='=>'int'], 'transliterator_create_inverse' => ['?Transliterator', 'transliterator'=>'Transliterator'], @@ -14008,8 +13986,8 @@ return [ 'uasort' => ['true', '&rw_array'=>'array', 'callback'=>'callable(mixed,mixed):int'], 'ucfirst' => ['string', 'string'=>'string'], 'UConverter::__construct' => ['void', 'destination_encoding='=>'?string', 'source_encoding='=>'?string'], -'UConverter::convert' => ['string', 'string'=>'string', 'reverse='=>'bool'], -'UConverter::fromUCallback' => ['mixed', 'reason'=>'int', 'source'=>'string', 'codePoint'=>'string', '&w_error'=>'int'], +'UConverter::convert' => ['string', 'str'=>'string', 'reverse='=>'bool'], +'UConverter::fromUCallback' => ['string|int|array|null', 'reason'=>'int', 'source'=>'array', 'codePoint'=>'int', '&w_error'=>'int'], 'UConverter::getAliases' => ['array|false|null', 'name'=>'string'], 'UConverter::getAvailable' => ['array'], 'UConverter::getDestinationEncoding' => ['string|false|null'], @@ -14020,12 +13998,12 @@ return [ 'UConverter::getSourceType' => ['int|false|null'], 'UConverter::getStandards' => ['?array'], 'UConverter::getSubstChars' => ['string|false|null'], -'UConverter::reasonText' => ['string', 'reason='=>'int'], +'UConverter::reasonText' => ['string', 'reason'=>'int'], 'UConverter::setDestinationEncoding' => ['bool', 'encoding'=>'string'], 'UConverter::setSourceEncoding' => ['bool', 'encoding'=>'string'], 'UConverter::setSubstChars' => ['bool', 'chars'=>'string'], 'UConverter::toUCallback' => ['string|int|array|null', 'reason'=>'int', 'source'=>'string', 'codeUnits'=>'string', '&w_error'=>'int'], -'UConverter::transcode' => ['string', 'string'=>'string', 'toEncoding'=>'string', 'fromEncoding'=>'string', 'options='=>'?array'], +'UConverter::transcode' => ['string', 'str'=>'string', 'toEncoding'=>'string', 'fromEncoding'=>'string', 'options='=>'?array'], 'ucwords' => ['string', 'string'=>'string', 'separators='=>'string'], 'udm_add_search_limit' => ['bool', 'agent'=>'resource', 'var'=>'int', 'value'=>'string'], 'udm_alloc_agent' => ['resource', 'dbaddr'=>'string', 'dbmode='=>'string'], @@ -14239,7 +14217,7 @@ return [ 'UnexpectedValueException::getTrace' => ['list\',args?:array}>'], 'UnexpectedValueException::getTraceAsString' => ['string'], 'uniqid' => ['non-empty-string', 'prefix='=>'string', 'more_entropy='=>'bool'], -'unixtojd' => ['int', 'timestamp='=>'?int'], +'unixtojd' => ['int|false', 'timestamp='=>'?int'], 'unlink' => ['bool', 'filename'=>'string', 'context='=>'resource'], 'unpack' => ['array|false', 'format'=>'string', 'string'=>'string', 'offset='=>'int'], 'unregister_tick_function' => ['void', 'callback'=>'callable'], @@ -14502,17 +14480,12 @@ return [ 'wddx_packet_start' => ['resource|false', 'comment='=>'string'], 'wddx_serialize_value' => ['string|false', 'value'=>'mixed', 'comment='=>'string'], 'wddx_serialize_vars' => ['string|false', 'var_name'=>'mixed', '...vars='=>'mixed'], -'WeakMap::__construct' => ['void'], 'WeakMap::count' => ['int'], -'WeakMap::current' => ['mixed'], -'WeakMap::key' => ['object'], -'WeakMap::next' => ['void'], +'WeakMap::getIterator' => ['Iterator'], 'WeakMap::offsetExists' => ['bool', 'object'=>'object'], 'WeakMap::offsetGet' => ['mixed', 'object'=>'object'], 'WeakMap::offsetSet' => ['void', 'object'=>'object', 'value'=>'mixed'], 'WeakMap::offsetUnset' => ['void', 'object'=>'object'], -'WeakMap::rewind' => ['void'], -'WeakMap::valid' => ['bool'], 'Weakref::acquire' => ['bool'], 'Weakref::get' => ['object'], 'Weakref::release' => ['bool'], @@ -14728,7 +14701,7 @@ return [ 'xml_parser_create' => ['XMLParser', 'encoding='=>'?string'], 'xml_parser_create_ns' => ['XMLParser', 'encoding='=>'?string', 'separator='=>'string'], 'xml_parser_free' => ['bool', 'parser'=>'XMLParser'], -'xml_parser_get_option' => ['string', 'parser'=>'XMLParser', 'option'=>'int'], +'xml_parser_get_option' => ['string|int', 'parser'=>'XMLParser', 'option'=>'int'], 'xml_parser_set_option' => ['bool', 'parser'=>'XMLParser', 'option'=>'int', 'value'=>'mixed'], 'xml_set_character_data_handler' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], 'xml_set_default_handler' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], @@ -14753,18 +14726,18 @@ return [ 'XMLReader::expand' => ['DOMNode|false', 'baseNode='=>'?DOMNode'], 'XMLReader::getAttribute' => ['?string', 'name'=>'string'], 'XMLReader::getAttributeNo' => ['?string', 'index'=>'int'], -'XMLReader::getAttributeNs' => ['?string', 'name'=>'string', 'namespaceuri'=>'string'], +'XMLReader::getAttributeNs' => ['?string', 'name'=>'string', 'namespace'=>'string'], 'XMLReader::getParserProperty' => ['bool', 'property'=>'int'], 'XMLReader::isValid' => ['bool'], 'XMLReader::lookupNamespace' => ['?string', 'prefix'=>'string'], 'XMLReader::moveToAttribute' => ['bool', 'name'=>'string'], 'XMLReader::moveToAttributeNo' => ['bool', 'index'=>'int'], -'XMLReader::moveToAttributeNs' => ['bool', 'localname'=>'string', 'namespaceuri'=>'string'], +'XMLReader::moveToAttributeNs' => ['bool', 'name'=>'string', 'namespace'=>'string'], 'XMLReader::moveToElement' => ['bool'], 'XMLReader::moveToFirstAttribute' => ['bool'], 'XMLReader::moveToNextAttribute' => ['bool'], -'XMLReader::next' => ['bool', 'localname='=>'string'], -'XMLReader::open' => ['bool', 'uri'=>'string', 'encoding='=>'?string', 'options='=>'int'], +'XMLReader::next' => ['bool', 'name='=>'?string'], +'XMLReader::open' => ['bool|XmlReader', 'uri'=>'string', 'encoding='=>'?string', 'flags='=>'int'], 'XMLReader::read' => ['bool'], 'XMLReader::readInnerXML' => ['string'], 'XMLReader::readOuterXML' => ['string'], @@ -14773,7 +14746,7 @@ return [ 'XMLReader::setRelaxNGSchema' => ['bool', 'filename'=>'?string'], 'XMLReader::setRelaxNGSchemaSource' => ['bool', 'source'=>'?string'], 'XMLReader::setSchema' => ['bool', 'filename'=>'?string'], -'XMLReader::XML' => ['bool', 'source'=>'string', 'encoding='=>'?string', 'options='=>'int'], +'XMLReader::XML' => ['bool|XMLReader', 'source'=>'string', 'encoding='=>'?string', 'flags='=>'int'], 'XMLWriter::endAttribute' => ['bool'], 'XMLWriter::endCdata' => ['bool'], 'XMLWriter::endComment' => ['bool'], @@ -14866,13 +14839,13 @@ return [ 'XsltProcessor::getSecurityPrefs' => ['int'], 'XSLTProcessor::hasExsltSupport' => ['bool'], 'XSLTProcessor::importStylesheet' => ['bool', 'stylesheet'=>'object'], -'XSLTProcessor::registerPHPFunctions' => ['void', 'functions='=>'mixed'], +'XSLTProcessor::registerPHPFunctions' => ['void', 'functions='=>'array|string|null'], 'XSLTProcessor::removeParameter' => ['bool', 'namespace'=>'string', 'name'=>'string'], 'XSLTProcessor::setParameter' => ['bool', 'namespace'=>'string', 'name'=>'string', 'value'=>'string'], 'XSLTProcessor::setParameter\'1' => ['bool', 'namespace'=>'string', 'options'=>'array'], 'XSLTProcessor::setProfiling' => ['bool', 'filename'=>'?string'], 'XsltProcessor::setSecurityPrefs' => ['int', 'preferences'=>'int'], -'XSLTProcessor::transformToDoc' => ['DOMDocument|false', 'document'=>'DOMNode'], +'XSLTProcessor::transformToDoc' => ['DOMDocument|false', 'document'=>'DOMNode', 'returnClass='=>'?string'], 'XSLTProcessor::transformToURI' => ['int', 'document'=>'DOMDocument', 'uri'=>'string'], 'XSLTProcessor::transformToXML' => ['string|false', 'document'=>'DOMDocument'], 'yac::__construct' => ['void', 'prefix='=>'string'], @@ -15778,7 +15751,7 @@ return [ 'zip_entry_compressedsize' => ['int', 'zip_entry'=>'resource'], 'zip_entry_compressionmethod' => ['string', 'zip_entry'=>'resource'], 'zip_entry_filesize' => ['int', 'zip_entry'=>'resource'], -'zip_entry_name' => ['string', 'zip_entry'=>'resource'], +'zip_entry_name' => ['string|false', 'zip_entry'=>'resource'], 'zip_entry_open' => ['bool', 'zip_dp'=>'resource', 'zip_entry'=>'resource', 'mode='=>'string'], 'zip_entry_read' => ['string|false', 'zip_entry'=>'resource', 'len='=>'int'], 'zip_open' => ['resource|int|false', 'filename'=>'string'], @@ -15806,8 +15779,8 @@ return [ 'ZipArchive::getStream' => ['resource|false', 'name'=>'string'], 'ZipArchive::getStreamIndex' => ['resource|false', 'index'=>'int', 'flags='=>'int'], 'ZipArchive::getStreamName' => ['resource|false', 'name'=>'string', 'flags='=>'int'], -'ZipArchive::isCompressionMethodSupported' => ['bool', 'method'=>'int', 'encode='=>'bool'], -'ZipArchive::isEncryptionMethodSupported' => ['bool', 'method'=>'int', 'encode='=>'bool'], +'ZipArchive::isCompressionMethodSupported' => ['bool', 'method'=>'int', 'enc='=>'bool'], +'ZipArchive::isEncryptionMethodSupported' => ['bool', 'method'=>'int', 'enc='=>'bool'], 'ZipArchive::locateName' => ['int|false', 'name'=>'string', 'flags='=>'int'], 'ZipArchive::open' => ['int|bool', 'filename'=>'string', 'flags='=>'int'], 'ZipArchive::registerCancelCallback' => ['bool', 'callback'=>'callable'], @@ -15818,9 +15791,9 @@ return [ 'ZipArchive::setArchiveComment' => ['bool', 'comment'=>'string'], 'ZipArchive::setCommentIndex' => ['bool', 'index'=>'int', 'comment'=>'string'], 'ZipArchive::setCommentName' => ['bool', 'name'=>'string', 'comment'=>'string'], -'ZipArchive::setCompressionIndex' => ['bool', 'index'=>'int', 'comp_method'=>'int', 'comp_flags='=>'int'], -'ZipArchive::setCompressionName' => ['bool', 'name'=>'string', 'comp_method'=>'int', 'comp_flags='=>'int'], -'ZipArchive::setEncryptionIndex' => ['bool', 'index'=>'int', 'method'=>'string', 'password='=>'?string'], +'ZipArchive::setCompressionIndex' => ['bool', 'index'=>'int', 'method'=>'int', 'compflags='=>'int'], +'ZipArchive::setCompressionName' => ['bool', 'name'=>'string', 'method'=>'int', 'compflags='=>'int'], +'ZipArchive::setEncryptionIndex' => ['bool', 'index'=>'int', 'method'=>'int', 'password='=>'?string'], 'ZipArchive::setEncryptionName' => ['bool', 'name'=>'string', 'method'=>'int', 'password='=>'?string'], 'ZipArchive::setExternalAttributesIndex' => ['bool', 'index'=>'int', 'opsys'=>'int', 'attr'=>'int', 'flags='=>'int'], 'ZipArchive::setExternalAttributesName' => ['bool', 'name'=>'string', 'opsys'=>'int', 'attr'=>'int', 'flags='=>'int'], diff --git a/vendor/vimeo/psalm/dictionaries/CallMap_71_delta.php b/vendor/vimeo/psalm/dictionaries/CallMap_71_delta.php index 93bb8cae..8f11f599 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap_71_delta.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap_71_delta.php @@ -30,7 +30,7 @@ return [ 'sapi_windows_cp_get' => ['int', 'kind='=>'string'], 'sapi_windows_cp_is_utf8' => ['bool'], 'sapi_windows_cp_set' => ['bool', 'codepage'=>'int'], - 'session_create_id' => ['string', 'prefix='=>'string'], + 'session_create_id' => ['string|false', 'prefix='=>'string'], 'session_gc' => ['int|false'], ], 'changed' => [ @@ -42,6 +42,10 @@ return [ 'old' => ['string|false', 'value'=>'IntlCalendar|DateTime|array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int}|array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}|string|int|float'], 'new' => ['string|false', 'value'=>'IntlCalendar|DateTimeInterface|array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int}|array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}|string|int|float'], ], + 'SessionHandler::gc' => [ + 'old' => ['bool', 'max_lifetime'=>'int'], + 'new' => ['int|false', 'max_lifetime'=>'int'], + ], 'SQLite3::createFunction' => [ 'old' => ['bool', 'name'=>'string', 'callback'=>'callable', 'argCount='=>'int'], 'new' => ['bool', 'name'=>'string', 'callback'=>'callable', 'argCount='=>'int', 'flags='=>'int'], diff --git a/vendor/vimeo/psalm/dictionaries/CallMap_72_delta.php b/vendor/vimeo/psalm/dictionaries/CallMap_72_delta.php index 1956ee7c..aedc76cd 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap_72_delta.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap_72_delta.php @@ -19,7 +19,7 @@ return [ 'DOMNodeList::count' => ['int'], 'ReflectionClass::isIterable' => ['bool'], 'ZipArchive::count' => ['int'], - 'ZipArchive::setEncryptionIndex' => ['bool', 'index'=>'int', 'method'=>'string', 'password='=>'string'], + 'ZipArchive::setEncryptionIndex' => ['bool', 'index'=>'int', 'method'=>'int', 'password='=>'string'], 'ZipArchive::setEncryptionName' => ['bool', 'name'=>'string', 'method'=>'int', 'password='=>'string'], 'ftp_append' => ['bool', 'ftp'=>'resource', 'remote_filename'=>'string', 'local_filename'=>'string', 'mode='=>'int'], 'hash_hmac_algos' => ['list'], @@ -103,7 +103,7 @@ return [ 'sodium_crypto_secretstream_xchacha20poly1305_init_pull' => ['string', 'header'=>'string', 'key'=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_init_push' => ['array', 'key'=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_keygen' => ['non-empty-string'], - 'sodium_crypto_secretstream_xchacha20poly1305_pull' => ['array', '&r_state'=>'string', 'ciphertext'=>'string', 'additional_data='=>'string'], + 'sodium_crypto_secretstream_xchacha20poly1305_pull' => ['array|false', '&r_state'=>'string', 'ciphertext'=>'string', 'additional_data='=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_push' => ['string', '&w_state'=>'string', 'message'=>'string', 'additional_data='=>'string', 'tag='=>'int'], 'sodium_crypto_secretstream_xchacha20poly1305_rekey' => ['void', '&w_state'=>'string'], 'sodium_crypto_shorthash' => ['string', 'message'=>'string', 'key'=>'string'], diff --git a/vendor/vimeo/psalm/dictionaries/CallMap_73_delta.php b/vendor/vimeo/psalm/dictionaries/CallMap_73_delta.php index 568603b6..d79026c3 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap_73_delta.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap_73_delta.php @@ -18,7 +18,7 @@ return [ 'added' => [ 'DateTime::createFromImmutable' => ['static', 'object'=>'DateTimeImmutable'], 'JsonException::__clone' => ['void'], - 'JsonException::__construct' => ['void'], + 'JsonException::__construct' => ['void', "message="=>"string", 'code='=>'int', 'previous='=>'?Throwable'], 'JsonException::__toString' => ['string'], 'JsonException::__wakeup' => ['void'], 'JsonException::getCode' => ['int'], @@ -77,8 +77,8 @@ return [ 'new' => ['bool|string', 'ldap'=>'resource', 'user='=>'string', 'old_password='=>'string', 'new_password='=>'string', '&w_controls='=>'array'], ], 'ldap_list' => [ - 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], - 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], + 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], + 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], ], 'ldap_mod_add' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], @@ -101,16 +101,16 @@ return [ 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'modifications_info'=>'array', 'controls='=>'array'], ], 'ldap_read' => [ - 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], - 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], + 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], + 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], ], 'ldap_rename' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'array'], ], 'ldap_search' => [ - 'old' => ['resource|false', 'ldap'=>'resource|resource[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], - 'new' => ['resource|false', 'ldap'=>'resource|resource[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], + 'old' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], + 'new' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], ], ], 'removed' => [ diff --git a/vendor/vimeo/psalm/dictionaries/CallMap_80_delta.php b/vendor/vimeo/psalm/dictionaries/CallMap_80_delta.php index 89b4bdfc..134b79a0 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap_80_delta.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap_80_delta.php @@ -28,6 +28,13 @@ return [ 'ReflectionParameter::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionProperty::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionUnionType::getTypes' => ['list'], + 'SplFixedArray::getIterator' => ['Iterator'], + 'WeakMap::count' => ['int'], + 'WeakMap::getIterator' => ['Iterator'], + 'WeakMap::offsetExists' => ['bool', 'object'=>'object'], + 'WeakMap::offsetGet' => ['mixed', 'object'=>'object'], + 'WeakMap::offsetSet' => ['void', 'object'=>'object', 'value'=>'mixed'], + 'WeakMap::offsetUnset' => ['void', 'object'=>'object'], 'fdiv' => ['float', 'num1'=>'float', 'num2'=>'float'], 'get_debug_type' => ['string', 'value'=>'mixed'], 'get_resource_id' => ['int', 'resource'=>'resource'], @@ -217,6 +224,10 @@ return [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], + 'mysqli_stmt::__construct' => [ + 'old' => ['void', 'mysql'=>'mysqli', 'query='=>'string'], + 'new' => ['void', 'mysql'=>'mysqli', 'query='=>'?string'], + ], 'NumberFormatter::__construct' => [ 'old' => ['void', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], 'new' => ['void', 'locale'=>'string', 'style'=>'int', 'pattern='=>'?string'], @@ -373,6 +384,14 @@ return [ 'old' => ['?Closure', 'object='=>'object'], 'new' => ['Closure', 'object='=>'?object'], ], + 'ReflectionObject::getConstants' => [ + 'old' => ['array'], + 'new' => ['array', 'filter='=>'?int'], + ], + 'ReflectionObject::getReflectionConstants' => [ + 'old' => ['list<\ReflectionClassConstant>'], + 'new' => ['list<\ReflectionClassConstant>', 'filter='=>'?int'], + ], 'ReflectionObject::newInstanceArgs' => [ 'old' => ['object', 'args='=>'list'], 'new' => ['object', 'args='=>'list|array'], @@ -461,6 +480,10 @@ return [ 'old' => ['string|false'], 'new' => ['string'], ], + 'XMLReader::next' => [ + 'old' => ['bool', 'name='=>'string'], + 'new' => ['bool', 'name='=>'?string'], + ], 'XMLWriter::startAttributeNs' => [ 'old' => ['bool', 'prefix'=>'string', 'name'=>'string', 'namespace'=>'?string'], 'new' => ['bool', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], @@ -478,8 +501,8 @@ return [ 'new' => ['string'], ], 'ZipArchive::setEncryptionIndex' => [ - 'old' => ['bool', 'index'=>'int', 'method'=>'string', 'password='=>'string'], - 'new' => ['bool', 'index'=>'int', 'method'=>'string', 'password='=>'?string'], + 'old' => ['bool', 'index'=>'int', 'method'=>'int', 'password='=>'string'], + 'new' => ['bool', 'index'=>'int', 'method'=>'int', 'password='=>'?string'], ], 'ZipArchive::setEncryptionName' => [ 'old' => ['bool', 'name'=>'string', 'method'=>'int', 'password='=>'string'], @@ -618,8 +641,8 @@ return [ 'new' => ['void', 'handle'=>'CurlHandle'], ], 'curl_copy_handle' => [ - 'old' => ['resource', 'ch'=>'resource'], - 'new' => ['CurlHandle', 'handle'=>'CurlHandle'], + 'old' => ['resource|false', 'ch'=>'resource'], + 'new' => ['CurlHandle|false', 'handle'=>'CurlHandle'], ], 'curl_errno' => [ 'old' => ['int', 'ch'=>'resource'], @@ -798,8 +821,8 @@ return [ 'new' => ['DOMElement', 'node'=>'SimpleXMLElement'], ], 'easter_date' => [ - 'old' => ['int', 'year='=>'int'], - 'new' => ['int', 'year='=>'?int'], + 'old' => ['int', 'year='=>'int', 'mode='=>'int'], + 'new' => ['int', 'year='=>'?int', 'mode='=>'int'], ], 'easter_days' => [ 'old' => ['int', 'year='=>'int', 'mode='=>'int'], @@ -934,8 +957,8 @@ return [ 'new' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], ], 'get_class_methods' => [ - 'old' => ['list|null', 'object_or_class'=>'mixed'], - 'new' => ['list', 'object_or_class'=>'object|class-string'], + 'old' => ['list|null', 'object_or_class'=>'mixed'], + 'new' => ['list', 'object_or_class'=>'object|class-string'], ], 'get_headers' => [ 'old' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'?resource'], @@ -982,12 +1005,12 @@ return [ 'new' => ['string|false', 'stream'=>'resource', 'length='=>'?int'], ], 'gzputs' => [ - 'old' => ['int', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], - 'new' => ['int', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], + 'old' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], + 'new' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], ], 'gzwrite' => [ - 'old' => ['int', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], - 'new' => ['int', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], + 'old' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], + 'new' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], ], 'hash' => [ 'old' => ['string|false', 'algo'=>'string', 'data'=>'string', 'binary='=>'bool'], @@ -1506,8 +1529,8 @@ return [ 'new' => ['bool|string', 'ldap'=>'resource', 'user='=>'string', 'old_password='=>'string', 'new_password='=>'string', '&w_controls='=>'array|null'], ], 'ldap_list' => [ - 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], - 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], + 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], + 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_rename_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'array'], @@ -1546,16 +1569,16 @@ return [ 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'modifications_info'=>'array', 'controls='=>'?array'], ], 'ldap_read' => [ - 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], - 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], + 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], + 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_rename' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], ], 'ldap_search' => [ - 'old' => ['resource|false', 'ldap'=>'resource|resource[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], - 'new' => ['resource|false', 'ldap'=>'resource|resource[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], + 'old' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], + 'new' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_set_rebind_proc' => [ 'old' => ['bool', 'ldap'=>'resource', 'callback'=>'callable'], @@ -1866,8 +1889,8 @@ return [ 'new' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'?string'], ], 'number_format' => [ - 'old' => ['string', 'num'=>'float|int', 'decimals='=>'int'], - 'new' => ['string', 'num'=>'float|int', 'decimals='=>'int', 'decimal_separator='=>'?string', 'thousands_separator='=>'?string'], + 'old' => ['string', 'num'=>'float', 'decimals='=>'int'], + 'new' => ['string', 'num'=>'float', 'decimals='=>'int', 'decimal_separator='=>'?string', 'thousands_separator='=>'?string'], ], 'numfmt_create' => [ 'old' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], @@ -2186,28 +2209,28 @@ return [ 'new' => ['bool', 'semaphore'=>'SysvSemaphore'], ], 'session_cache_expire' => [ - 'old' => ['int', 'value='=>'int'], - 'new' => ['int', 'value='=>'?int'], + 'old' => ['int|false', 'value='=>'int'], + 'new' => ['int|false', 'value='=>'?int'], ], 'session_cache_limiter' => [ - 'old' => ['string', 'value='=>'string'], - 'new' => ['string', 'value='=>'?string'], + 'old' => ['string|false', 'value='=>'string'], + 'new' => ['string|false', 'value='=>'?string'], ], 'session_id' => [ 'old' => ['string|false', 'id='=>'string'], 'new' => ['string|false', 'id='=>'?string'], ], 'session_module_name' => [ - 'old' => ['string', 'module='=>'string'], - 'new' => ['string', 'module='=>'?string'], + 'old' => ['string|false', 'module='=>'string'], + 'new' => ['string|false', 'module='=>'?string'], ], 'session_name' => [ 'old' => ['string|false', 'name='=>'string'], 'new' => ['string|false', 'name='=>'?string'], ], 'session_save_path' => [ - 'old' => ['string', 'path='=>'string'], - 'new' => ['string', 'path='=>'?string'], + 'old' => ['string|false', 'path='=>'string'], + 'new' => ['string|false', 'path='=>'?string'], ], 'session_set_cookie_params' => [ 'old' => ['bool', 'lifetime'=>'int', 'path='=>'string', 'domain='=>'string', 'secure='=>'bool', 'httponly='=>'bool'], @@ -2578,8 +2601,8 @@ return [ 'new' => ['int', 'mask='=>'?int'], ], 'unixtojd' => [ - 'old' => ['int', 'timestamp='=>'int'], - 'new' => ['int', 'timestamp='=>'?int'], + 'old' => ['int|false', 'timestamp='=>'int'], + 'new' => ['int|false', 'timestamp='=>'?int'], ], 'xml_get_current_byte_index' => [ 'old' => ['int|false', 'parser'=>'resource'], @@ -2618,8 +2641,8 @@ return [ 'new' => ['bool', 'parser'=>'XMLParser'], ], 'xml_parser_get_option' => [ - 'old' => ['string|false', 'parser'=>'resource', 'option'=>'int'], - 'new' => ['string', 'parser'=>'XMLParser', 'option'=>'int'], + 'old' => ['string|int', 'parser'=>'resource', 'option'=>'int'], + 'new' => ['string|int', 'parser'=>'XMLParser', 'option'=>'int'], ], 'xml_parser_set_option' => [ 'old' => ['bool', 'parser'=>'resource', 'option'=>'int', 'value'=>'mixed'], @@ -2862,7 +2885,7 @@ return [ 'ldap_control_paged_result' => ['bool', 'link_identifier'=>'resource', 'pagesize'=>'int', 'iscritical='=>'bool', 'cookie='=>'string'], 'ldap_control_paged_result_response' => ['bool', 'link_identifier'=>'resource', 'result_identifier'=>'resource', '&w_cookie'=>'string', '&w_estimated'=>'int'], 'ldap_sort' => ['bool', 'link_identifier'=>'resource', 'result_identifier'=>'resource', 'sortfilter'=>'string'], - 'number_format\'1' => ['string', 'num'=>'float|int', 'decimals'=>'int', 'decimal_separator'=>'?string', 'thousands_separator'=>'?string'], + 'number_format\'1' => ['string', 'num'=>'float', 'decimals'=>'int', 'decimal_separator'=>'?string', 'thousands_separator'=>'?string'], 'png2wbmp' => ['bool', 'pngname'=>'string', 'wbmpname'=>'string', 'dest_height'=>'int', 'dest_width'=>'int', 'threshold'=>'int'], 'read_exif_data' => ['array', 'filename'=>'string', 'sections_needed='=>'string', 'sub_arrays='=>'bool', 'read_thumbnail='=>'bool'], 'Reflection::export' => ['?string', 'r'=>'reflector', 'return='=>'bool'], @@ -2883,6 +2906,11 @@ return [ 'SimpleXMLIterator::next' => ['void'], 'SimpleXMLIterator::hasChildren' => ['bool'], 'SimpleXMLIterator::getChildren' => ['?SimpleXMLIterator'], + 'SplFixedArray::current' => ['mixed'], + 'SplFixedArray::key' => ['int'], + 'SplFixedArray::next' => ['void'], + 'SplFixedArray::rewind' => ['void'], + 'SplFixedArray::valid' => ['bool'], 'SplTempFileObject::fgetss' => ['string', 'allowable_tags='=>'string'], 'xmlrpc_decode' => ['mixed', 'xml'=>'string', 'encoding='=>'string'], 'xmlrpc_decode_request' => ['?array', 'xml'=>'string', '&w_method'=>'string', 'encoding='=>'string'], diff --git a/vendor/vimeo/psalm/dictionaries/CallMap_81_delta.php b/vendor/vimeo/psalm/dictionaries/CallMap_81_delta.php index ded1f5e4..3bd304ea 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap_81_delta.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap_81_delta.php @@ -619,8 +619,8 @@ return [ 'new' => ['array|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry', 'attribute'=>'string'], ], 'ldap_list' => [ - 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], - 'new' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], + 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], + 'new' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_mod_add' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], @@ -679,8 +679,8 @@ return [ 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result', '&w_error_code'=>'int', '&w_matched_dn='=>'string', '&w_error_message='=>'string', '&w_referrals='=>'array', '&w_controls='=>'array'], ], 'ldap_read' => [ - 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], - 'new' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], + 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], + 'new' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_rename' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], @@ -695,8 +695,8 @@ return [ 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn='=>'?string', 'password='=>'?string', 'mech='=>'?string', 'realm='=>'?string', 'authc_id='=>'?string', 'authz_id='=>'?string', 'props='=>'?string'], ], 'ldap_search' => [ - 'old' => ['resource|false', 'ldap'=>'resource|resource[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], - 'new' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], + 'old' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], + 'new' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_set_option' => [ 'old' => ['bool', 'ldap'=>'resource|null', 'option'=>'int', 'value'=>'mixed'], diff --git a/vendor/vimeo/psalm/dictionaries/CallMap_82_delta.php b/vendor/vimeo/psalm/dictionaries/CallMap_82_delta.php index 555ea008..47ded4fb 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap_82_delta.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap_82_delta.php @@ -41,9 +41,17 @@ return [ 'old' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'string', '...handler_params='=>'string'], 'new' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'?string', 'permission='=>'int', 'map_size='=>'int', 'flags='=>'?int'], ], + 'iterator_count' => [ + 'old' => ['0|positive-int', 'iterator'=>'Traversable'], + 'new' => ['0|positive-int', 'iterator'=>'Traversable|array'], + ], + 'iterator_to_array' => [ + 'old' => ['array', 'iterator'=>'Traversable', 'preserve_keys='=>'bool'], + 'new' => ['array', 'iterator'=>'Traversable|array', 'preserve_keys='=>'bool'], + ], 'str_split' => [ 'old' => ['non-empty-list', 'string'=>'string', 'length='=>'positive-int'], - 'new' => ['list', 'string'=>'string', 'length='=>'positive-int'], + 'new' => ['list', 'string'=>'string', 'length='=>'positive-int'], ], ], diff --git a/vendor/vimeo/psalm/dictionaries/CallMap_historical.php b/vendor/vimeo/psalm/dictionaries/CallMap_historical.php index 2b14a8a5..a88bab36 100644 --- a/vendor/vimeo/psalm/dictionaries/CallMap_historical.php +++ b/vendor/vimeo/psalm/dictionaries/CallMap_historical.php @@ -293,7 +293,6 @@ return [ 'COMPersistHelper::SaveToStream' => ['int', 'stream'=>''], 'COMPersistHelper::__construct' => ['void', 'variant'=>'object'], 'CURLFile::__construct' => ['void', 'filename'=>'string', 'mime_type='=>'string', 'posted_filename='=>'string'], - 'CURLFile::__wakeup' => ['void'], 'CURLFile::getFilename' => ['string'], 'CURLFile::getMimeType' => ['string'], 'CURLFile::getPostFilename' => ['string'], @@ -1623,8 +1622,6 @@ return [ 'GEOSWKTWriter::setRoundingPrecision' => ['void', 'prec'=>'int'], 'GEOSWKTWriter::setTrim' => ['void', 'trim'=>'bool'], 'GEOSWKTWriter::write' => ['string', 'geom'=>'GEOSGeometry'], - 'GMP::__construct' => ['void'], - 'GMP::__toString' => ['numeric-string'], 'GearmanClient::__construct' => ['void'], 'GearmanClient::addOptions' => ['bool', 'options'=>'int'], 'GearmanClient::addServer' => ['bool', 'host='=>'string', 'port='=>'int'], @@ -1738,7 +1735,6 @@ return [ 'Gender\Gender::get' => ['int', 'name'=>'string', 'country='=>'int'], 'Gender\Gender::isNick' => ['array', 'name0'=>'string', 'name1'=>'string', 'country='=>'int'], 'Gender\Gender::similarNames' => ['array', 'name'=>'string', 'country='=>'int'], - 'Generator::__wakeup' => ['void'], 'Generator::current' => ['mixed'], 'Generator::getReturn' => ['mixed'], 'Generator::key' => ['mixed'], @@ -3265,7 +3261,7 @@ return [ 'Iterator::rewind' => ['void'], 'Iterator::valid' => ['bool'], 'IteratorAggregate::getIterator' => ['Traversable'], - 'IteratorIterator::__construct' => ['void', 'it'=>'Traversable'], + 'IteratorIterator::__construct' => ['void', 'iterator'=>'Traversable', 'class='=>'?string'], 'IteratorIterator::current' => ['mixed'], 'IteratorIterator::getInnerIterator' => ['Iterator'], 'IteratorIterator::key' => ['mixed'], @@ -3387,14 +3383,14 @@ return [ 'LevelDBWriteBatch::delete' => ['', 'key'=>'', 'write_options='=>'array'], 'LevelDBWriteBatch::put' => ['', 'key'=>'', 'value'=>'', 'write_options='=>'array'], 'LevelDBWriteBatch::set' => ['', 'key'=>'', 'value'=>'', 'write_options='=>'array'], - 'LimitIterator::__construct' => ['void', 'iterator'=>'Iterator', 'offset='=>'int', 'count='=>'int'], + 'LimitIterator::__construct' => ['void', 'iterator'=>'Iterator', 'offset='=>'int', 'limit='=>'int'], 'LimitIterator::current' => ['mixed'], 'LimitIterator::getInnerIterator' => ['Iterator'], 'LimitIterator::getPosition' => ['int'], 'LimitIterator::key' => ['mixed'], 'LimitIterator::next' => ['void'], 'LimitIterator::rewind' => ['void'], - 'LimitIterator::seek' => ['int', 'position'=>'int'], + 'LimitIterator::seek' => ['int', 'offset'=>'int'], 'LimitIterator::valid' => ['bool'], 'Locale::acceptFromHttp' => ['string|false', 'header'=>'string'], 'Locale::canonicalize' => ['string', 'locale'=>'string'], @@ -3539,14 +3535,14 @@ return [ 'Memcached::touchByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'expiration='=>'int'], 'MessageFormatter::__construct' => ['void', 'locale'=>'string', 'pattern'=>'string'], 'MessageFormatter::create' => ['MessageFormatter', 'locale'=>'string', 'pattern'=>'string'], - 'MessageFormatter::format' => ['false|string', 'args'=>'array'], - 'MessageFormatter::formatMessage' => ['false|string', 'locale'=>'string', 'pattern'=>'string', 'args'=>'array'], + 'MessageFormatter::format' => ['false|string', 'values'=>'array'], + 'MessageFormatter::formatMessage' => ['false|string', 'locale'=>'string', 'pattern'=>'string', 'values'=>'array'], 'MessageFormatter::getErrorCode' => ['int'], 'MessageFormatter::getErrorMessage' => ['string'], 'MessageFormatter::getLocale' => ['string'], 'MessageFormatter::getPattern' => ['string'], - 'MessageFormatter::parse' => ['array|false', 'value'=>'string'], - 'MessageFormatter::parseMessage' => ['array|false', 'locale'=>'string', 'pattern'=>'string', 'source'=>'string'], + 'MessageFormatter::parse' => ['array|false', 'string'=>'string'], + 'MessageFormatter::parseMessage' => ['array|false', 'locale'=>'string', 'pattern'=>'string', 'message'=>'string'], 'MessageFormatter::setPattern' => ['bool', 'pattern'=>'string'], 'Mongo::__construct' => ['void', 'server='=>'string', 'options='=>'array', 'driver_options='=>'array'], 'Mongo::__get' => ['MongoDB', 'dbname'=>'string'], @@ -3735,7 +3731,7 @@ return [ 'MongoDBRef::create' => ['array', 'collection'=>'string', 'id'=>'mixed', 'database='=>'string'], 'MongoDBRef::get' => ['?array', 'db'=>'MongoDB', 'ref'=>'array'], 'MongoDBRef::isRef' => ['bool', 'ref'=>'mixed'], - 'MongoDB\BSON\Binary::__construct' => ['void', 'data' => 'string', 'type' => 'int'], + 'MongoDB\BSON\Binary::__construct' => ['void', 'data' => 'string', 'type=' => 'int'], 'MongoDB\BSON\Binary::getData' => ['string'], 'MongoDB\BSON\Binary::getType' => ['int'], 'MongoDB\BSON\Binary::__toString' => ['string'], @@ -4191,7 +4187,7 @@ return [ 'MongoWriteConcernException::getTrace' => ['list\',args?:array}>'], 'MongoWriteConcernException::getTraceAsString' => ['string'], 'MultipleIterator::__construct' => ['void', 'flags='=>'int'], - 'MultipleIterator::attachIterator' => ['void', 'iterator'=>'Iterator', 'infos='=>'string'], + 'MultipleIterator::attachIterator' => ['void', 'iterator'=>'Iterator', 'info='=>'string|int|null'], 'MultipleIterator::containsIterator' => ['bool', 'iterator'=>'Iterator'], 'MultipleIterator::countIterators' => ['int'], 'MultipleIterator::current' => ['array|false'], @@ -4273,20 +4269,20 @@ return [ 'NumberFormatter::__construct' => ['void', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], 'NumberFormatter::create' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], 'NumberFormatter::format' => ['string|false', 'num'=>'', 'type='=>'int'], - 'NumberFormatter::formatCurrency' => ['string|false', 'num'=>'float', 'currency'=>'string'], - 'NumberFormatter::getAttribute' => ['int|false', 'attr'=>'int'], + 'NumberFormatter::formatCurrency' => ['string|false', 'amount'=>'float', 'currency'=>'string'], + 'NumberFormatter::getAttribute' => ['int|float|false', 'attribute'=>'int'], 'NumberFormatter::getErrorCode' => ['int'], 'NumberFormatter::getErrorMessage' => ['string'], 'NumberFormatter::getLocale' => ['string', 'type='=>'int'], 'NumberFormatter::getPattern' => ['string|false'], - 'NumberFormatter::getSymbol' => ['string|false', 'attr'=>'int'], - 'NumberFormatter::getTextAttribute' => ['string|false', 'attr'=>'int'], - 'NumberFormatter::parse' => ['float|false', 'string'=>'string', 'type='=>'int', '&rw_position='=>'int'], - 'NumberFormatter::parseCurrency' => ['float|false', 'string'=>'string', '&w_currency'=>'string', '&rw_position='=>'int'], - 'NumberFormatter::setAttribute' => ['bool', 'attr'=>'int', 'value'=>''], + 'NumberFormatter::getSymbol' => ['string|false', 'symbol'=>'int'], + 'NumberFormatter::getTextAttribute' => ['string|false', 'attribute'=>'int'], + 'NumberFormatter::parse' => ['int|float|false', 'string'=>'string', 'type='=>'int', '&rw_offset='=>'int'], + 'NumberFormatter::parseCurrency' => ['float|false', 'string'=>'string', '&w_currency'=>'string', '&rw_offset='=>'int'], + 'NumberFormatter::setAttribute' => ['bool', 'attribute'=>'int', 'value'=>'int|float'], 'NumberFormatter::setPattern' => ['bool', 'pattern'=>'string'], - 'NumberFormatter::setSymbol' => ['bool', 'attr'=>'int', 'symbol'=>'string'], - 'NumberFormatter::setTextAttribute' => ['bool', 'attr'=>'int', 'value'=>'string'], + 'NumberFormatter::setSymbol' => ['bool', 'symbol'=>'int', 'value'=>'string'], + 'NumberFormatter::setTextAttribute' => ['bool', 'attribute'=>'int', 'value'=>'string'], 'OAuth::__construct' => ['void', 'consumer_key'=>'string', 'consumer_secret'=>'string', 'signature_method='=>'string', 'auth_type='=>'int'], 'OAuth::disableDebug' => ['bool'], 'OAuth::disableRedirects' => ['bool'], @@ -4710,8 +4706,6 @@ return [ 'PDFlib::utf32_to_utf16' => ['string', 'utf32string'=>'string', 'ordering'=>'string'], 'PDFlib::utf8_to_utf16' => ['string', 'utf8string'=>'string', 'ordering'=>'string'], 'PDO::__construct' => ['void', 'dsn'=>'string', 'username='=>'?string', 'password='=>'?string', 'options='=>'?array'], - 'PDO::__sleep' => ['list'], - 'PDO::__wakeup' => ['void'], 'PDO::beginTransaction' => ['bool'], 'PDO::commit' => ['bool'], 'PDO::cubrid_schema' => ['array', 'schema_type'=>'int', 'table_name='=>'string', 'col_name='=>'string'], @@ -4749,8 +4743,6 @@ return [ 'PDOException::getPrevious' => ['?Throwable'], 'PDOException::getTrace' => ['list\',args?:array}>'], 'PDOException::getTraceAsString' => ['string'], - 'PDOStatement::__sleep' => ['list'], - 'PDOStatement::__wakeup' => ['void'], 'PDOStatement::bindColumn' => ['bool', 'column'=>'string|int', '&rw_var'=>'mixed', 'type='=>'int', 'maxLength='=>'int', 'driverOptions='=>'mixed'], 'PDOStatement::bindParam' => ['bool', 'param'=>'string|int', '&rw_var'=>'mixed', 'type='=>'int', 'maxLength='=>'int', 'driverOptions='=>'mixed'], 'PDOStatement::bindValue' => ['bool', 'param'=>'string|int', 'value'=>'mixed', 'type='=>'int'], @@ -5758,7 +5750,7 @@ return [ 'Reflection::export' => ['?string', 'r'=>'reflector', 'return='=>'bool'], 'Reflection::getModifierNames' => ['list', 'modifiers'=>'int'], 'ReflectionClass::__clone' => ['void'], - 'ReflectionClass::__construct' => ['void', 'argument'=>'object|class-string'], + 'ReflectionClass::__construct' => ['void', 'objectOrClass'=>'object|class-string'], 'ReflectionClass::__toString' => ['string'], 'ReflectionClass::export' => ['?string', 'argument'=>'string|object', 'return='=>'bool'], 'ReflectionClass::getConstant' => ['mixed', 'name'=>'string'], @@ -5792,7 +5784,7 @@ return [ 'ReflectionClass::hasConstant' => ['bool', 'name'=>'string'], 'ReflectionClass::hasMethod' => ['bool', 'name'=>'string'], 'ReflectionClass::hasProperty' => ['bool', 'name'=>'string'], - 'ReflectionClass::implementsInterface' => ['bool', 'interface_name'=>'interface-string|ReflectionClass'], + 'ReflectionClass::implementsInterface' => ['bool', 'interface'=>'interface-string|ReflectionClass'], 'ReflectionClass::inNamespace' => ['bool'], 'ReflectionClass::isAbstract' => ['bool'], 'ReflectionClass::isAnonymous' => ['bool'], @@ -5810,7 +5802,7 @@ return [ 'ReflectionClass::newInstanceArgs' => ['object', 'args='=>'list'], 'ReflectionClass::newInstanceWithoutConstructor' => ['object'], 'ReflectionClass::setStaticPropertyValue' => ['void', 'name'=>'string', 'value'=>'mixed'], - 'ReflectionClassConstant::__construct' => ['void', 'class'=>'mixed', 'name'=>'string'], + 'ReflectionClassConstant::__construct' => ['void', 'class'=>'object|class-string', 'constant'=>'string'], 'ReflectionClassConstant::__toString' => ['string'], 'ReflectionClassConstant::export' => ['string', 'class'=>'mixed', 'name'=>'string', 'return='=>'bool'], 'ReflectionClassConstant::getDeclaringClass' => ['ReflectionClass'], @@ -5836,7 +5828,7 @@ return [ 'ReflectionExtension::info' => ['void'], 'ReflectionExtension::isPersistent' => ['bool'], 'ReflectionExtension::isTemporary' => ['bool'], - 'ReflectionFunction::__construct' => ['void', 'name'=>'callable-string|Closure'], + 'ReflectionFunction::__construct' => ['void', 'function'=>'callable-string|Closure'], 'ReflectionFunction::__toString' => ['string'], 'ReflectionFunction::export' => ['?string', 'name'=>'string', 'return='=>'bool'], 'ReflectionFunction::getClosure' => ['Closure'], @@ -5896,7 +5888,7 @@ return [ 'ReflectionFunctionAbstract::isUserDefined' => ['bool'], 'ReflectionFunctionAbstract::isVariadic' => ['bool'], 'ReflectionFunctionAbstract::returnsReference' => ['bool'], - 'ReflectionGenerator::__construct' => ['void', 'generator'=>'object'], + 'ReflectionGenerator::__construct' => ['void', 'generator'=>'Generator'], 'ReflectionGenerator::getExecutingFile' => ['string'], 'ReflectionGenerator::getExecutingGenerator' => ['Generator'], 'ReflectionGenerator::getExecutingLine' => ['int'], @@ -5946,14 +5938,14 @@ return [ 'ReflectionMethod::isUserDefined' => ['bool'], 'ReflectionMethod::isVariadic' => ['bool'], 'ReflectionMethod::returnsReference' => ['bool'], - 'ReflectionMethod::setAccessible' => ['void', 'visible'=>'bool'], + 'ReflectionMethod::setAccessible' => ['void', 'accessible'=>'bool'], 'ReflectionNamedType::__clone' => ['void'], 'ReflectionNamedType::__toString' => ['string'], 'ReflectionNamedType::allowsNull' => ['bool'], 'ReflectionNamedType::getName' => ['string'], 'ReflectionNamedType::isBuiltin' => ['bool'], 'ReflectionObject::__clone' => ['void'], - 'ReflectionObject::__construct' => ['void', 'argument'=>'object'], + 'ReflectionObject::__construct' => ['void', 'object'=>'object'], 'ReflectionObject::__toString' => ['string'], 'ReflectionObject::export' => ['?string', 'argument'=>'object', 'return='=>'bool'], 'ReflectionObject::getConstant' => ['mixed', 'name'=>'string'], @@ -5987,7 +5979,7 @@ return [ 'ReflectionObject::hasConstant' => ['bool', 'name'=>'string'], 'ReflectionObject::hasMethod' => ['bool', 'name'=>'string'], 'ReflectionObject::hasProperty' => ['bool', 'name'=>'string'], - 'ReflectionObject::implementsInterface' => ['bool', 'interface_name'=>'ReflectionClass|string'], + 'ReflectionObject::implementsInterface' => ['bool', 'interface'=>'ReflectionClass|interface-string'], 'ReflectionObject::inNamespace' => ['bool'], 'ReflectionObject::isAbstract' => ['bool'], 'ReflectionObject::isAnonymous' => ['bool'], @@ -6007,7 +5999,7 @@ return [ 'ReflectionObject::newInstanceWithoutConstructor' => ['object'], 'ReflectionObject::setStaticPropertyValue' => ['void', 'name'=>'string', 'value'=>'string'], 'ReflectionParameter::__clone' => ['void'], - 'ReflectionParameter::__construct' => ['void', 'function'=>'', 'parameter'=>''], + 'ReflectionParameter::__construct' => ['void', 'function'=>'string|array|object', 'param'=>'int|string'], 'ReflectionParameter::__toString' => ['string'], 'ReflectionParameter::allowsNull' => ['bool'], 'ReflectionParameter::canBePassedByValue' => ['bool'], @@ -6029,7 +6021,7 @@ return [ 'ReflectionParameter::isPassedByReference' => ['bool'], 'ReflectionParameter::isVariadic' => ['bool'], 'ReflectionProperty::__clone' => ['void'], - 'ReflectionProperty::__construct' => ['void', 'class'=>'', 'name'=>'string'], + 'ReflectionProperty::__construct' => ['void', 'class'=>'object|class-string', 'property'=>'string'], 'ReflectionProperty::__toString' => ['string'], 'ReflectionProperty::export' => ['?string', 'class'=>'mixed', 'name'=>'string', 'return='=>'bool'], 'ReflectionProperty::getDeclaringClass' => ['ReflectionClass'], @@ -6043,7 +6035,7 @@ return [ 'ReflectionProperty::isProtected' => ['bool'], 'ReflectionProperty::isPublic' => ['bool'], 'ReflectionProperty::isStatic' => ['bool'], - 'ReflectionProperty::setAccessible' => ['void', 'visible'=>'bool'], + 'ReflectionProperty::setAccessible' => ['void', 'accessible'=>'bool'], 'ReflectionProperty::setValue' => ['void', 'object'=>'null|object', 'value'=>''], 'ReflectionProperty::setValue\'1' => ['void', 'value'=>''], 'ReflectionType::__clone' => ['void'], @@ -6076,13 +6068,13 @@ return [ 'RegexIterator::setMode' => ['void', 'mode'=>'int'], 'RegexIterator::setPregFlags' => ['void', 'pregFlags'=>'int'], 'RegexIterator::valid' => ['bool'], - 'ResourceBundle::__construct' => ['void', 'locale'=>'string', 'bundlename'=>'string', 'fallback='=>'bool'], + 'ResourceBundle::__construct' => ['void', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'ResourceBundle::count' => ['int'], - 'ResourceBundle::create' => ['?ResourceBundle', 'locale'=>'string', 'bundlename'=>'string', 'fallback='=>'bool'], + 'ResourceBundle::create' => ['?ResourceBundle', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'ResourceBundle::get' => ['mixed', 'index'=>'string|int', 'fallback='=>'bool'], 'ResourceBundle::getErrorCode' => ['int'], 'ResourceBundle::getErrorMessage' => ['string'], - 'ResourceBundle::getLocales' => ['array', 'bundlename'=>'string'], + 'ResourceBundle::getLocales' => ['array|false', 'bundle'=>'string'], 'Runkit_Sandbox::__construct' => ['void', 'options='=>'array'], 'Runkit_Sandbox_Parent' => [''], 'Runkit_Sandbox_Parent::__construct' => ['void'], @@ -6193,8 +6185,8 @@ return [ 'SNMP::getnext' => ['string|array|false', 'objectId'=>'string|array'], 'SNMP::set' => ['bool', 'objectId'=>'string|array', 'type'=>'string|array', 'value'=>'string|array'], 'SNMP::setSecurity' => ['bool', 'securityLevel'=>'string', 'authProtocol='=>'string', 'authPassphrase='=>'string', 'privacyProtocol='=>'string', 'privacyPassphrase='=>'string', 'contextName='=>'string', 'contextEngineId='=>'string'], - 'SNMP::walk' => ['array|false', 'objectId'=>'string', 'suffixAsKey='=>'bool', 'maxRepetitions='=>'int', 'nonRepeaters='=>'int'], - 'SQLite3::__construct' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'?string'], + 'SNMP::walk' => ['array|false', 'objectId'=>'array|string', 'suffixAsKey='=>'bool', 'maxRepetitions='=>'int', 'nonRepeaters='=>'int'], + 'SQLite3::__construct' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'string'], 'SQLite3::busyTimeout' => ['bool', 'milliseconds'=>'int'], 'SQLite3::changes' => ['int'], 'SQLite3::close' => ['bool'], @@ -6208,7 +6200,7 @@ return [ 'SQLite3::lastErrorMsg' => ['string'], 'SQLite3::lastInsertRowID' => ['int'], 'SQLite3::loadExtension' => ['bool', 'name'=>'string'], - 'SQLite3::open' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'?string'], + 'SQLite3::open' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'string'], 'SQLite3::openBlob' => ['resource|false', 'table'=>'string', 'column'=>'string', 'rowid'=>'int', 'dbname='=>'string'], 'SQLite3::prepare' => ['SQLite3Stmt|false', 'query'=>'string'], 'SQLite3::query' => ['SQLite3Result|false', 'query'=>'string'], @@ -6619,9 +6611,9 @@ return [ 'SessionHandler::close' => ['bool'], 'SessionHandler::create_sid' => ['string'], 'SessionHandler::destroy' => ['bool', 'id'=>'string'], - 'SessionHandler::gc' => ['bool', 'maxlifetime'=>'int'], - 'SessionHandler::open' => ['bool', 'save_path'=>'string', 'session_name'=>'string'], - 'SessionHandler::read' => ['string', 'id'=>'string'], + 'SessionHandler::gc' => ['bool', 'max_lifetime'=>'int'], + 'SessionHandler::open' => ['bool', 'path'=>'string', 'name'=>'string'], + 'SessionHandler::read' => ['string|false', 'id'=>'string'], 'SessionHandler::write' => ['bool', 'id'=>'string', 'data'=>'string'], 'SessionHandlerInterface::close' => ['bool'], 'SessionHandlerInterface::destroy' => ['bool', 'id'=>'string'], @@ -6634,26 +6626,26 @@ return [ 'SessionUpdateTimestampHandler::validateId' => ['char', 'id'=>'string'], 'SessionUpdateTimestampHandlerInterface::updateTimestamp' => ['bool', 'key'=>'string', 'value'=>'string'], 'SessionUpdateTimestampHandlerInterface::validateId' => ['bool', 'key'=>'string'], - 'SimpleXMLElement::__construct' => ['void', 'data'=>'string', 'options='=>'int', 'data_is_url='=>'bool', 'ns='=>'string', 'is_prefix='=>'bool'], + 'SimpleXMLElement::__construct' => ['void', 'data'=>'string', 'options='=>'int', 'dataIsURL='=>'bool', 'namespaceOrPrefix='=>'string', 'isPrefix='=>'bool'], 'SimpleXMLElement::__get' => ['SimpleXMLElement', 'name'=>'string'], 'SimpleXMLElement::__toString' => ['string'], - 'SimpleXMLElement::addAttribute' => ['void', 'name'=>'string', 'value='=>'string', 'ns='=>'string'], - 'SimpleXMLElement::addChild' => ['SimpleXMLElement', 'name'=>'string', 'value='=>'string', 'ns='=>'string'], + 'SimpleXMLElement::addAttribute' => ['void', 'qualifiedName'=>'string', 'value'=>'string', 'namespace='=>'?string'], + 'SimpleXMLElement::addChild' => ['?SimpleXMLElement', 'qualifiedName'=>'string', 'value='=>'?string', 'namespace='=>'?string'], 'SimpleXMLElement::asXML' => ['string|bool', 'filename'=>'string'], 'SimpleXMLElement::asXML\'1' => ['string|false'], - 'SimpleXMLElement::attributes' => ['?SimpleXMLElement', 'ns='=>'string', 'is_prefix='=>'bool'], - 'SimpleXMLElement::children' => ['SimpleXMLElement', 'ns='=>'string', 'is_prefix='=>'bool'], + 'SimpleXMLElement::attributes' => ['?SimpleXMLElement', 'namespaceOrPrefix='=>'?string', 'isPrefix='=>'bool'], + 'SimpleXMLElement::children' => ['?SimpleXMLElement', 'namespaceOrPrefix='=>'?string', 'isPrefix='=>'bool'], 'SimpleXMLElement::count' => ['int'], - 'SimpleXMLElement::getDocNamespaces' => ['string[]', 'recursive='=>'bool', 'from_root='=>'bool'], + 'SimpleXMLElement::getDocNamespaces' => ['array', 'recursive='=>'bool', 'fromRoot='=>'bool'], 'SimpleXMLElement::getName' => ['string'], - 'SimpleXMLElement::getNamespaces' => ['string[]', 'recursive='=>'bool'], + 'SimpleXMLElement::getNamespaces' => ['array', 'recursive='=>'bool'], 'SimpleXMLElement::offsetExists' => ['bool', 'offset'=>'int|string'], 'SimpleXMLElement::offsetGet' => ['SimpleXMLElement', 'offset'=>'int|string'], 'SimpleXMLElement::offsetSet' => ['void', 'offset'=>'int|string', 'value'=>'mixed'], 'SimpleXMLElement::offsetUnset' => ['void', 'offset'=>'int|string'], - 'SimpleXMLElement::registerXPathNamespace' => ['bool', 'prefix'=>'string', 'ns'=>'string'], + 'SimpleXMLElement::registerXPathNamespace' => ['bool', 'prefix'=>'string', 'namespace'=>'string'], 'SimpleXMLElement::saveXML' => ['string|bool', 'filename='=>'string'], - 'SimpleXMLElement::xpath' => ['SimpleXMLElement[]|false', 'path'=>'string'], + 'SimpleXMLElement::xpath' => ['SimpleXMLElement[]|false|null', 'expression'=>'string'], 'SimpleXMLIterator::current' => ['?SimpleXMLIterator'], 'SimpleXMLIterator::getChildren' => ['?SimpleXMLIterator'], 'SimpleXMLIterator::hasChildren' => ['bool'], @@ -7496,10 +7488,10 @@ return [ 'SplDoublyLinkedList::isEmpty' => ['bool'], 'SplDoublyLinkedList::key' => ['int'], 'SplDoublyLinkedList::next' => ['void'], - 'SplDoublyLinkedList::offsetExists' => ['bool', 'index'=>'mixed'], - 'SplDoublyLinkedList::offsetGet' => ['mixed', 'index'=>'mixed'], - 'SplDoublyLinkedList::offsetSet' => ['void', 'index'=>'mixed', 'value'=>'mixed'], - 'SplDoublyLinkedList::offsetUnset' => ['void', 'index'=>'mixed'], + 'SplDoublyLinkedList::offsetExists' => ['bool', 'index'=>'int'], + 'SplDoublyLinkedList::offsetGet' => ['mixed', 'index'=>'int'], + 'SplDoublyLinkedList::offsetSet' => ['void', 'index'=>'?int', 'value'=>'mixed'], + 'SplDoublyLinkedList::offsetUnset' => ['void', 'index'=>'int'], 'SplDoublyLinkedList::pop' => ['mixed'], 'SplDoublyLinkedList::prev' => ['void'], 'SplDoublyLinkedList::push' => ['void', 'value'=>'mixed'], @@ -7515,7 +7507,6 @@ return [ 'SplEnum::getConstList' => ['array', 'include_default='=>'bool'], 'SplFileInfo::__construct' => ['void', 'filename'=>'string'], 'SplFileInfo::__toString' => ['string'], - 'SplFileInfo::__wakeup' => ['void'], 'SplFileInfo::getATime' => ['int|false'], 'SplFileInfo::getBasename' => ['string', 'suffix='=>'string'], 'SplFileInfo::getCTime' => ['int|false'], @@ -7989,7 +7980,7 @@ return [ 'Transliterator::getErrorCode' => ['int'], 'Transliterator::getErrorMessage' => ['string'], 'Transliterator::listIDs' => ['array'], - 'Transliterator::transliterate' => ['string|false', 'subject'=>'string', 'start='=>'int', 'end='=>'int'], + 'Transliterator::transliterate' => ['string|false', 'string'=>'string', 'start='=>'int', 'end='=>'int'], 'TypeError::__clone' => ['void'], 'TypeError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'TypeError::__toString' => ['string'], @@ -8001,8 +7992,8 @@ return [ 'TypeError::getTrace' => ['list\',args?:array}>'], 'TypeError::getTraceAsString' => ['string'], 'UConverter::__construct' => ['void', 'destination_encoding='=>'?string', 'source_encoding='=>'?string'], - 'UConverter::convert' => ['string', 'string'=>'string', 'reverse='=>'bool'], - 'UConverter::fromUCallback' => ['mixed', 'reason'=>'int', 'source'=>'string', 'codePoint'=>'string', '&w_error'=>'int'], + 'UConverter::convert' => ['string', 'str'=>'string', 'reverse='=>'bool'], + 'UConverter::fromUCallback' => ['string|int|array|null', 'reason'=>'int', 'source'=>'array', 'codePoint'=>'int', '&w_error'=>'int'], 'UConverter::getAliases' => ['array|false|null', 'name'=>'string'], 'UConverter::getAvailable' => ['array'], 'UConverter::getDestinationEncoding' => ['string|false|null'], @@ -8013,12 +8004,12 @@ return [ 'UConverter::getSourceType' => ['int|false|null'], 'UConverter::getStandards' => ['?array'], 'UConverter::getSubstChars' => ['string|false|null'], - 'UConverter::reasonText' => ['string', 'reason='=>'int'], + 'UConverter::reasonText' => ['string', 'reason'=>'int'], 'UConverter::setDestinationEncoding' => ['bool', 'encoding'=>'string'], 'UConverter::setSourceEncoding' => ['bool', 'encoding'=>'string'], 'UConverter::setSubstChars' => ['bool', 'chars'=>'string'], 'UConverter::toUCallback' => ['string|int|array|null', 'reason'=>'int', 'source'=>'string', 'codeUnits'=>'string', '&w_error'=>'int'], - 'UConverter::transcode' => ['string', 'string'=>'string', 'toEncoding'=>'string', 'fromEncoding'=>'string', 'options='=>'?array'], + 'UConverter::transcode' => ['string', 'str'=>'string', 'toEncoding'=>'string', 'fromEncoding'=>'string', 'options='=>'?array'], 'UnderflowException::__clone' => ['void'], 'UnderflowException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'UnderflowException::__toString' => ['string'], @@ -8183,17 +8174,6 @@ return [ 'Vtiful\Kernel\Validation::validationType' => ['?Vtiful\Kernel\Validation', 'type'=>'int'], 'Vtiful\Kernel\Validation::valueList' => ['?Vtiful\Kernel\Validation', 'value_list'=>'array'], 'Vtiful\Kernel\Validation::valueNumber' => ['?Vtiful\Kernel\Validation', 'value_number'=>'int'], - 'WeakMap::__construct' => ['void'], - 'WeakMap::count' => ['int'], - 'WeakMap::current' => ['mixed'], - 'WeakMap::key' => ['object'], - 'WeakMap::next' => ['void'], - 'WeakMap::offsetExists' => ['bool', 'object'=>'object'], - 'WeakMap::offsetGet' => ['mixed', 'object'=>'object'], - 'WeakMap::offsetSet' => ['void', 'object'=>'object', 'value'=>'mixed'], - 'WeakMap::offsetUnset' => ['void', 'object'=>'object'], - 'WeakMap::rewind' => ['void'], - 'WeakMap::valid' => ['bool'], 'Weakref::acquire' => ['bool'], 'Weakref::get' => ['object'], 'Weakref::release' => ['bool'], @@ -8252,23 +8232,23 @@ return [ 'XMLDiff\File::merge' => ['string', 'src'=>'string', 'diff'=>'string'], 'XMLDiff\Memory::diff' => ['string', 'from'=>'string', 'to'=>'string'], 'XMLDiff\Memory::merge' => ['string', 'src'=>'string', 'diff'=>'string'], - 'XMLReader::XML' => ['bool', 'source'=>'string', 'encoding='=>'?string', 'options='=>'int'], + 'XMLReader::XML' => ['bool|XMLReader', 'source'=>'string', 'encoding='=>'?string', 'flags='=>'int'], 'XMLReader::close' => ['bool'], 'XMLReader::expand' => ['DOMNode|false', 'baseNode='=>'?DOMNode'], 'XMLReader::getAttribute' => ['?string', 'name'=>'string'], 'XMLReader::getAttributeNo' => ['?string', 'index'=>'int'], - 'XMLReader::getAttributeNs' => ['?string', 'name'=>'string', 'namespaceuri'=>'string'], + 'XMLReader::getAttributeNs' => ['?string', 'name'=>'string', 'namespace'=>'string'], 'XMLReader::getParserProperty' => ['bool', 'property'=>'int'], 'XMLReader::isValid' => ['bool'], 'XMLReader::lookupNamespace' => ['?string', 'prefix'=>'string'], 'XMLReader::moveToAttribute' => ['bool', 'name'=>'string'], 'XMLReader::moveToAttributeNo' => ['bool', 'index'=>'int'], - 'XMLReader::moveToAttributeNs' => ['bool', 'localname'=>'string', 'namespaceuri'=>'string'], + 'XMLReader::moveToAttributeNs' => ['bool', 'name'=>'string', 'namespace'=>'string'], 'XMLReader::moveToElement' => ['bool'], 'XMLReader::moveToFirstAttribute' => ['bool'], 'XMLReader::moveToNextAttribute' => ['bool'], - 'XMLReader::next' => ['bool', 'localname='=>'string'], - 'XMLReader::open' => ['bool', 'uri'=>'string', 'encoding='=>'?string', 'options='=>'int'], + 'XMLReader::next' => ['bool', 'name='=>'string'], + 'XMLReader::open' => ['bool|XmlReader', 'uri'=>'string', 'encoding='=>'?string', 'flags='=>'int'], 'XMLReader::read' => ['bool'], 'XMLReader::readInnerXML' => ['string'], 'XMLReader::readOuterXML' => ['string'], @@ -8322,12 +8302,12 @@ return [ 'XSLTProcessor::getParameter' => ['string|false', 'namespace'=>'string', 'name'=>'string'], 'XSLTProcessor::hasExsltSupport' => ['bool'], 'XSLTProcessor::importStylesheet' => ['bool', 'stylesheet'=>'object'], - 'XSLTProcessor::registerPHPFunctions' => ['void', 'functions='=>'mixed'], + 'XSLTProcessor::registerPHPFunctions' => ['void', 'functions='=>'array|string|null'], 'XSLTProcessor::removeParameter' => ['bool', 'namespace'=>'string', 'name'=>'string'], 'XSLTProcessor::setParameter' => ['bool', 'namespace'=>'string', 'name'=>'string', 'value'=>'string'], 'XSLTProcessor::setParameter\'1' => ['bool', 'namespace'=>'string', 'options'=>'array'], 'XSLTProcessor::setProfiling' => ['bool', 'filename'=>'?string'], - 'XSLTProcessor::transformToDoc' => ['DOMDocument|false', 'document'=>'DOMNode'], + 'XSLTProcessor::transformToDoc' => ['DOMDocument|false', 'document'=>'DOMNode', 'returnClass='=>'?string'], 'XSLTProcessor::transformToURI' => ['int', 'document'=>'DOMDocument', 'uri'=>'string'], 'XSLTProcessor::transformToXML' => ['string|false', 'document'=>'DOMDocument'], 'Xcom::__construct' => ['void', 'fabric_url='=>'string', 'fabric_token='=>'string', 'capability_token='=>'string'], @@ -9216,8 +9196,8 @@ return [ 'ZipArchive::getNameIndex' => ['string|false', 'index'=>'int', 'flags='=>'int'], 'ZipArchive::getStatusString' => ['string|false'], 'ZipArchive::getStream' => ['resource|false', 'name'=>'string'], - 'ZipArchive::isCompressionMethodSupported' => ['bool', 'method'=>'int', 'encode='=>'bool'], - 'ZipArchive::isEncryptionMethodSupported' => ['bool', 'method'=>'int', 'encode='=>'bool'], + 'ZipArchive::isCompressionMethodSupported' => ['bool', 'method'=>'int', 'enc='=>'bool'], + 'ZipArchive::isEncryptionMethodSupported' => ['bool', 'method'=>'int', 'enc='=>'bool'], 'ZipArchive::locateName' => ['int|false', 'name'=>'string', 'flags='=>'int'], 'ZipArchive::open' => ['int|bool', 'filename'=>'string', 'flags='=>'int'], 'ZipArchive::registerCancelCallback' => ['bool', 'callback'=>'callable'], @@ -9228,8 +9208,8 @@ return [ 'ZipArchive::setArchiveComment' => ['bool', 'comment'=>'string'], 'ZipArchive::setCommentIndex' => ['bool', 'index'=>'int', 'comment'=>'string'], 'ZipArchive::setCommentName' => ['bool', 'name'=>'string', 'comment'=>'string'], - 'ZipArchive::setCompressionIndex' => ['bool', 'index'=>'int', 'comp_method'=>'int', 'comp_flags='=>'int'], - 'ZipArchive::setCompressionName' => ['bool', 'name'=>'string', 'comp_method'=>'int', 'comp_flags='=>'int'], + 'ZipArchive::setCompressionIndex' => ['bool', 'index'=>'int', 'method'=>'int', 'compflags='=>'int'], + 'ZipArchive::setCompressionName' => ['bool', 'name'=>'string', 'method'=>'int', 'compflags='=>'int'], 'ZipArchive::setExternalAttributesIndex' => ['bool', 'index'=>'int', 'opsys'=>'int', 'attr'=>'int', 'flags='=>'int'], 'ZipArchive::setExternalAttributesName' => ['bool', 'name'=>'string', 'opsys'=>'int', 'attr'=>'int', 'flags='=>'int'], 'ZipArchive::setMtimeIndex' => ['bool', 'index'=>'int', 'timestamp'=>'int', 'flags='=>'int'], @@ -9401,9 +9381,7 @@ return [ 'array_uintersect_assoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable', '...rest='=>'array|callable(mixed,mixed):int'], 'array_uintersect_uassoc' => ['array', 'array'=>'array', 'rest'=>'array', 'data_compare_func'=>'callable(mixed,mixed):int', 'key_compare_func'=>'callable(mixed,mixed):int'], 'array_uintersect_uassoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', 'arg5'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], - 'array_unique' => ['array', 'array'=>'array', 'flags='=>'0'], - 'array_unique\'1' => ['array', 'array'=>'array', 'flags='=>'1'], - 'array_unique\'2' => ['array', 'array'=>'array', 'flags='=>'2|5'], + 'array_unique' => ['array', 'array'=>'array', 'flags='=>'int'], 'array_unshift' => ['int', '&rw_array'=>'array', '...values'=>'mixed'], 'array_values' => ['list', 'array'=>'array'], 'array_walk' => ['bool', '&rw_array'=>'array', 'callback'=>'callable', 'arg='=>'mixed'], @@ -9500,7 +9478,7 @@ return [ 'call_user_func_array' => ['mixed|false', 'callback'=>'callable', 'args'=>'list'], 'call_user_method' => ['mixed', 'method_name'=>'string', 'object'=>'object', 'parameter='=>'mixed', '...args='=>'mixed'], 'call_user_method_array' => ['mixed', 'method_name'=>'string', 'object'=>'object', 'params'=>'list'], - 'ceil' => ['float', 'num'=>'float'], + 'ceil' => ['float', 'num'=>'float|int'], 'chdb::__construct' => ['void', 'pathname'=>'string'], 'chdb::get' => ['string', 'key'=>'string'], 'chdb_create' => ['bool', 'pathname'=>'string', 'data'=>'array'], @@ -9763,7 +9741,7 @@ return [ 'cubrid_unbuffered_query' => ['resource', 'query'=>'string', 'conn_identifier='=>''], 'cubrid_version' => ['string'], 'curl_close' => ['void', 'ch'=>'resource'], - 'curl_copy_handle' => ['resource', 'ch'=>'resource'], + 'curl_copy_handle' => ['resource|false', 'ch'=>'resource'], 'curl_errno' => ['int', 'ch'=>'resource'], 'curl_error' => ['string', 'ch'=>'resource'], 'curl_escape' => ['string|false', 'ch'=>'resource', 'string'=>'string'], @@ -9812,7 +9790,7 @@ return [ 'date_get_last_errors' => ['array{warning_count:int,warnings:array,error_count:int,errors:array}|false'], 'date_interval_create_from_date_string' => ['DateInterval', 'datetime'=>'string'], 'date_interval_format' => ['string', 'object'=>'DateInterval', 'format'=>'string'], - 'date_isodate_set' => ['DateTime|false', 'object'=>'DateTime', 'year'=>'int', 'week'=>'int', 'dayOfWeek='=>'int|mixed'], + 'date_isodate_set' => ['DateTime', 'object'=>'DateTime', 'year'=>'int', 'week'=>'int', 'dayOfWeek='=>'int'], 'date_modify' => ['DateTime|false', 'object'=>'DateTime', 'modifier'=>'string'], 'date_offset_get' => ['int|false', 'object'=>'DateTimeInterface'], 'date_parse' => ['array|false', 'datetime'=>'string'], @@ -9841,7 +9819,7 @@ return [ 'datefmt_get_timezone_id' => ['string|false', 'formatter'=>'IntlDateFormatter'], 'datefmt_is_lenient' => ['bool', 'formatter'=>'IntlDateFormatter'], 'datefmt_localtime' => ['array|false', 'formatter'=>'IntlDateFormatter', 'string'=>'string', '&rw_offset='=>'int'], - 'datefmt_parse' => ['int|false', 'formatter'=>'IntlDateFormatter', 'string'=>'string', '&rw_offset='=>'int'], + 'datefmt_parse' => ['float|int|false', 'formatter'=>'IntlDateFormatter', 'string'=>'string', '&rw_offset='=>'int'], 'datefmt_set_calendar' => ['bool', 'formatter'=>'IntlDateFormatter', 'calendar'=>'IntlCalendar|int|null'], 'datefmt_set_lenient' => ['void', 'formatter'=>'IntlDateFormatter', 'lenient'=>'bool'], 'datefmt_set_pattern' => ['bool', 'formatter'=>'IntlDateFormatter', 'pattern'=>'string'], @@ -9903,20 +9881,20 @@ return [ 'db2_tableprivileges' => [''], 'db2_tables' => ['resource|false', 'connection'=>'resource', 'qualifier='=>'?string', 'schema='=>'?string', 'table_name='=>'?string', 'table_type='=>'?string'], 'dba_close' => ['void', 'dba'=>'resource'], - 'dba_delete' => ['bool', 'key'=>'string', 'dba'=>'resource'], - 'dba_exists' => ['bool', 'key'=>'string', 'dba'=>'resource'], - 'dba_fetch' => ['string|false', 'key'=>'string', 'skip'=>'int', 'dba'=>'resource'], - 'dba_fetch\'1' => ['string|false', 'key'=>'string', 'skip'=>'resource'], + 'dba_delete' => ['bool', 'key'=>'array|string', 'dba'=>'resource'], + 'dba_exists' => ['bool', 'key'=>'array|string', 'dba'=>'resource'], + 'dba_fetch' => ['string|false', 'key'=>'array|string', 'skip'=>'int', 'dba'=>'resource'], + 'dba_fetch\'1' => ['string|false', 'key'=>'array|string', 'skip'=>'resource'], 'dba_firstkey' => ['string', 'dba'=>'resource'], 'dba_handlers' => ['array', 'full_info='=>'bool'], - 'dba_insert' => ['bool', 'key'=>'string', 'value'=>'string', 'dba'=>'resource'], + 'dba_insert' => ['bool', 'key'=>'array|string', 'value'=>'string', 'dba'=>'resource'], 'dba_key_split' => ['array|false', 'key'=>'string|false|null'], 'dba_list' => ['array'], 'dba_nextkey' => ['string', 'dba'=>'resource'], 'dba_open' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'string', '...handler_params='=>'string'], 'dba_optimize' => ['bool', 'dba'=>'resource'], 'dba_popen' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'string', '...handler_params='=>'string'], - 'dba_replace' => ['bool', 'key'=>'string', 'value'=>'string', 'dba'=>'resource'], + 'dba_replace' => ['bool', 'key'=>'array|string', 'value'=>'string', 'dba'=>'resource'], 'dba_sync' => ['bool', 'dba'=>'resource'], 'dbase_add_record' => ['bool', 'dbase_identifier'=>'resource', 'record'=>'array'], 'dbase_close' => ['bool', 'dbase_identifier'=>'resource'], @@ -10048,7 +10026,7 @@ return [ 'dotnet_load' => ['int', 'assembly_name'=>'string', 'datatype_name='=>'string', 'codepage='=>'int'], 'doubleval' => ['float', 'value'=>'mixed'], 'each' => ['array{0:int|string,key:int|string,1:mixed,value:mixed}', '&r_arr'=>'array'], - 'easter_date' => ['int', 'year='=>'int'], + 'easter_date' => ['int', 'year='=>'int', 'mode='=>'int'], 'easter_days' => ['int', 'year='=>'int', 'mode='=>'int'], 'echo' => ['void', 'arg1'=>'string', '...args='=>'string'], 'eio_busy' => ['resource', 'delay'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], @@ -10514,7 +10492,7 @@ return [ 'finfo_set_flags' => ['bool', 'finfo'=>'resource', 'flags'=>'int'], 'floatval' => ['float', 'value'=>'mixed'], 'flock' => ['bool', 'stream'=>'resource', 'operation'=>'int', '&w_would_block='=>'int'], - 'floor' => ['float', 'num'=>'float'], + 'floor' => ['float', 'num'=>'float|int'], 'flush' => ['void'], 'fmod' => ['float', 'num1'=>'float', 'num2'=>'float'], 'fnmatch' => ['bool', 'pattern'=>'string', 'filename'=>'string', 'flags='=>'int'], @@ -10699,8 +10677,8 @@ return [ 'get_called_class' => ['class-string'], 'get_cfg_var' => ['string|false', 'option'=>'string'], 'get_class' => ['class-string', 'object='=>'object'], - 'get_class_methods' => ['list|null', 'object_or_class'=>'mixed'], - 'get_class_vars' => ['array', 'class'=>'string'], + 'get_class_methods' => ['list|null', 'object_or_class'=>'mixed'], + 'get_class_vars' => ['array', 'class'=>'string'], 'get_current_user' => ['string'], 'get_declared_classes' => ['list'], 'get_declared_interfaces' => ['list'], @@ -10749,7 +10727,7 @@ return [ 'gettimeofday' => ['array'], 'gettimeofday\'1' => ['float', 'as_float='=>'true'], 'gettype' => ['string', 'value'=>'mixed'], - 'glob' => ['list|false', 'pattern'=>'string', 'flags='=>'int'], + 'glob' => ['list|false', 'pattern'=>'non-empty-string', 'flags='=>'int<1, max>'], 'gmdate' => ['string', 'format'=>'string', 'timestamp='=>'int'], 'gmmktime' => ['int|false', 'hour='=>'int', 'minute='=>'int', 'second='=>'int', 'month='=>'int', 'day='=>'int', 'year='=>'int'], 'gmp_abs' => ['GMP', 'num'=>'GMP|string|int'], @@ -10899,20 +10877,20 @@ return [ 'gzdeflate' => ['string|false', 'data'=>'string', 'level='=>'int', 'encoding='=>'int'], 'gzencode' => ['string|false', 'data'=>'string', 'level='=>'int', 'encoding='=>'int'], 'gzeof' => ['bool', 'stream'=>'resource'], - 'gzfile' => ['list', 'filename'=>'string', 'use_include_path='=>'int'], + 'gzfile' => ['list|false', 'filename'=>'string', 'use_include_path='=>'int'], 'gzgetc' => ['string|false', 'stream'=>'resource'], 'gzgets' => ['string|false', 'stream'=>'resource', 'length='=>'int'], 'gzgetss' => ['string|false', 'zp'=>'resource', 'length'=>'int', 'allowable_tags='=>'string'], 'gzinflate' => ['string|false', 'data'=>'string', 'max_length='=>'int'], 'gzopen' => ['resource|false', 'filename'=>'string', 'mode'=>'string', 'use_include_path='=>'int'], 'gzpassthru' => ['int', 'stream'=>'resource'], - 'gzputs' => ['int', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], + 'gzputs' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], 'gzread' => ['string|0', 'stream'=>'resource', 'length'=>'int'], 'gzrewind' => ['bool', 'stream'=>'resource'], 'gzseek' => ['int', 'stream'=>'resource', 'offset'=>'int', 'whence='=>'int'], 'gztell' => ['int|false', 'stream'=>'resource'], 'gzuncompress' => ['string|false', 'data'=>'string', 'max_length='=>'int'], - 'gzwrite' => ['int', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], + 'gzwrite' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], 'hash' => ['string|false', 'algo'=>'string', 'data'=>'string', 'binary='=>'bool'], 'hashTableObj::clear' => ['void'], 'hashTableObj::get' => ['string', 'key'=>'string'], @@ -12127,7 +12105,7 @@ return [ 'ldap_count_entries' => ['int', 'ldap'=>'resource', 'result'=>'resource'], 'ldap_delete' => ['bool', 'ldap'=>'resource', 'dn'=>'string'], 'ldap_delete_ext' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'controls='=>'array'], - 'ldap_dn2ufn' => ['string', 'dn'=>'string'], + 'ldap_dn2ufn' => ['string|false', 'dn'=>'string'], 'ldap_err2str' => ['string', 'errno'=>'int'], 'ldap_errno' => ['int', 'ldap'=>'resource'], 'ldap_error' => ['string', 'ldap'=>'resource'], @@ -12143,7 +12121,7 @@ return [ 'ldap_get_option' => ['bool', 'ldap'=>'resource', 'option'=>'int', '&w_value='=>'array|string|int'], 'ldap_get_values' => ['array|false', 'ldap'=>'resource', 'entry'=>'resource', 'attribute'=>'string'], 'ldap_get_values_len' => ['array|false', 'ldap'=>'resource', 'entry'=>'resource', 'attribute'=>'string'], - 'ldap_list' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], + 'ldap_list' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], 'ldap_mod_add' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], 'ldap_mod_add_ext' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'ldap_mod_del' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], @@ -12157,11 +12135,11 @@ return [ 'ldap_next_reference' => ['resource|false', 'ldap'=>'resource', 'entry'=>'resource'], 'ldap_parse_reference' => ['bool', 'ldap'=>'resource', 'entry'=>'resource', '&w_referrals'=>'array'], 'ldap_parse_result' => ['bool', 'ldap'=>'resource', 'result'=>'resource', '&w_error_code'=>'int', '&w_matched_dn='=>'string', '&w_error_message='=>'string', '&w_referrals='=>'array', '&w_controls='=>'array'], - 'ldap_read' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], + 'ldap_read' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], 'ldap_rename' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool'], 'ldap_rename_ext' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'array'], 'ldap_sasl_bind' => ['bool', 'ldap'=>'resource', 'dn='=>'string', 'password='=>'string', 'mech='=>'string', 'realm='=>'string', 'authc_id='=>'string', 'authz_id='=>'string', 'props='=>'string'], - 'ldap_search' => ['resource|false', 'ldap'=>'resource|resource[]', 'base'=>'string', 'filter'=>'string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], + 'ldap_search' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], 'ldap_set_option' => ['bool', 'ldap'=>'resource|null', 'option'=>'int', 'value'=>'mixed'], 'ldap_set_rebind_proc' => ['bool', 'ldap'=>'resource', 'callback'=>'callable'], 'ldap_sort' => ['bool', 'link_identifier'=>'resource', 'result_identifier'=>'resource', 'sortfilter'=>'string'], @@ -12726,7 +12704,6 @@ return [ 'mysqli::commit' => ['bool', 'flags='=>'int', 'name='=>'string'], 'mysqli::connect' => ['null|false', 'hostname='=>'string', 'username='=>'string', 'password='=>'string', 'database='=>'string', 'port='=>'int', 'socket='=>'string'], 'mysqli::debug' => ['bool', 'options'=>'string'], - 'mysqli::disable_reads_from_master' => ['bool'], 'mysqli::dump_debug_info' => ['bool'], 'mysqli::escape_string' => ['string', 'string'=>'string'], 'mysqli::get_charset' => ['object'], @@ -12740,23 +12717,19 @@ return [ 'mysqli::next_result' => ['bool'], 'mysqli::options' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'mysqli::ping' => ['bool'], - 'mysqli::poll' => ['int|false', '&w_read'=>'array', '&w_write'=>'array', '&w_error'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], + 'mysqli::poll' => ['int|false', '&w_read'=>'?array', '&w_error'=>'?array', '&w_reject'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], 'mysqli::prepare' => ['mysqli_stmt|false', 'query'=>'string'], 'mysqli::query' => ['bool|mysqli_result', 'query'=>'string', 'result_mode='=>'int'], - 'mysqli::real_connect' => ['bool', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null', 'flags='=>'int'], + 'mysqli::real_connect' => ['bool', 'hostname='=>'?string', 'username='=>'?string', 'password='=>'?string', 'database='=>'?string', 'port='=>'?int', 'socket='=>'?string', 'flags='=>'int'], 'mysqli::real_escape_string' => ['string', 'string'=>'string'], 'mysqli::real_query' => ['bool', 'query'=>'string'], 'mysqli::reap_async_query' => ['mysqli_result|false'], 'mysqli::refresh' => ['bool', 'flags'=>'int'], 'mysqli::release_savepoint' => ['bool', 'name'=>'string'], 'mysqli::rollback' => ['bool', 'flags='=>'int', 'name='=>'string'], - 'mysqli::rpl_query_type' => ['int', 'query'=>'string'], 'mysqli::savepoint' => ['bool', 'name'=>'string'], 'mysqli::select_db' => ['bool', 'database'=>'string'], - 'mysqli::send_query' => ['bool', 'query'=>'string'], 'mysqli::set_charset' => ['bool', 'charset'=>'string'], - 'mysqli::set_local_infile_default' => ['void'], - 'mysqli::set_local_infile_handler' => ['bool', 'read_func='=>'callable'], 'mysqli::set_opt' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'mysqli::ssl_set' => ['bool', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'], 'mysqli::stat' => ['string|false'], @@ -12778,8 +12751,6 @@ return [ 'mysqli_debug' => ['true', 'options'=>'string'], 'mysqli_disable_reads_from_master' => ['bool', 'link'=>'mysqli'], 'mysqli_disable_rpl_parse' => ['bool', 'link'=>'mysqli'], - 'mysqli_driver::embedded_server_end' => ['void'], - 'mysqli_driver::embedded_server_start' => ['bool', 'start'=>'int', 'arguments'=>'array', 'groups'=>'array'], 'mysqli_dump_debug_info' => ['bool', 'mysql'=>'mysqli'], 'mysqli_embedded_server_end' => ['void'], 'mysqli_embedded_server_start' => ['bool', 'start'=>'int', 'arguments'=>'array', 'groups'=>'array'], @@ -12797,9 +12768,9 @@ return [ 'mysqli_fetch_array\'1' => ['array|false|null', 'result'=>'mysqli_result', 'mode='=>'1'], 'mysqli_fetch_array\'2' => ['list|false|null', 'result'=>'mysqli_result', 'mode='=>'2'], 'mysqli_fetch_assoc' => ['array|false|null', 'result'=>'mysqli_result'], - 'mysqli_fetch_field' => ['object|false', 'result'=>'mysqli_result'], - 'mysqli_fetch_field_direct' => ['object|false', 'result'=>'mysqli_result', 'index'=>'int'], - 'mysqli_fetch_fields' => ['stdClass[]', 'result'=>'mysqli_result'], + 'mysqli_fetch_field' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'result'=>'mysqli_result'], + 'mysqli_fetch_field_direct' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'result'=>'mysqli_result', 'index'=>'int'], + 'mysqli_fetch_fields' => ['list', 'result'=>'mysqli_result'], 'mysqli_fetch_lengths' => ['array|false', 'result'=>'mysqli_result'], 'mysqli_fetch_object' => ['object|false|null', 'result'=>'mysqli_result', 'class='=>'string', 'constructor_args='=>'array'], 'mysqli_fetch_row' => ['list|false|null', 'result'=>'mysqli_result'], @@ -12832,10 +12803,10 @@ return [ 'mysqli_num_rows' => ['int<0, max>|numeric-string', 'result'=>'mysqli_result'], 'mysqli_options' => ['bool', 'mysql'=>'mysqli', 'option'=>'int', 'value'=>'string|int'], 'mysqli_ping' => ['bool', 'mysql'=>'mysqli'], - 'mysqli_poll' => ['int|false', 'read'=>'array', 'write'=>'array', 'error'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], + 'mysqli_poll' => ['int|false', '&w_read'=>'?array', '&w_error'=>'?array', '&w_reject'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], 'mysqli_prepare' => ['mysqli_stmt|false', 'mysql'=>'mysqli', 'query'=>'string'], 'mysqli_query' => ['mysqli_result|bool', 'mysql'=>'mysqli', 'query'=>'string', 'result_mode='=>'int'], - 'mysqli_real_connect' => ['bool', 'mysql='=>'mysqli', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null', 'flags='=>'int'], + 'mysqli_real_connect' => ['bool', 'mysql'=>'mysqli', 'hostname='=>'?string', 'username='=>'?string', 'password='=>'?string', 'database='=>'?string', 'port='=>'?int', 'socket='=>'?string', 'flags='=>'int'], 'mysqli_real_escape_string' => ['string', 'mysql'=>'mysqli', 'string'=>'string'], 'mysqli_real_query' => ['bool', 'mysql'=>'mysqli', 'query'=>'string'], 'mysqli_reap_async_query' => ['mysqli_result|false', 'mysql'=>'mysqli'], @@ -12852,9 +12823,9 @@ return [ 'mysqli_result::fetch_array\'1' => ['array|false|null', 'mode='=>'1'], 'mysqli_result::fetch_array\'2' => ['list|false|null', 'mode='=>'2'], 'mysqli_result::fetch_assoc' => ['array|false|null'], - 'mysqli_result::fetch_field' => ['object|false'], - 'mysqli_result::fetch_field_direct' => ['object|false', 'index'=>'int'], - 'mysqli_result::fetch_fields' => ['stdClass[]'], + 'mysqli_result::fetch_field' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false'], + 'mysqli_result::fetch_field_direct' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'index'=>'int'], + 'mysqli_result::fetch_fields' => ['list'], 'mysqli_result::fetch_object' => ['object|false|null', 'class='=>'string', 'constructor_args='=>'array'], 'mysqli_result::fetch_row' => ['list|false|null'], 'mysqli_result::field_seek' => ['bool', 'index'=>'int'], @@ -12876,10 +12847,10 @@ return [ 'mysqli_sqlstate' => ['string', 'mysql'=>'mysqli'], 'mysqli_ssl_set' => ['true', 'mysql'=>'mysqli', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'], 'mysqli_stat' => ['string|false', 'mysql'=>'mysqli'], - 'mysqli_stmt::__construct' => ['void', 'mysql'=>'mysqli', 'query'=>'string'], + 'mysqli_stmt::__construct' => ['void', 'mysql'=>'mysqli', 'query='=>'string'], 'mysqli_stmt::attr_get' => ['int', 'attribute'=>'int'], 'mysqli_stmt::attr_set' => ['bool', 'attribute'=>'int', 'value'=>'int'], - 'mysqli_stmt::bind_param' => ['bool', 'types'=>'string', '&vars'=>'mixed', '&...args='=>'mixed'], + 'mysqli_stmt::bind_param' => ['bool', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'], 'mysqli_stmt::bind_result' => ['bool', '&w_var1'=>'', '&...w_vars='=>''], 'mysqli_stmt::close' => ['bool'], 'mysqli_stmt::data_seek' => ['void', 'offset'=>'int'], @@ -12899,7 +12870,7 @@ return [ 'mysqli_stmt_affected_rows' => ['int<-1, max>|numeric-string', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_attr_get' => ['int', 'statement'=>'mysqli_stmt', 'attribute'=>'int'], 'mysqli_stmt_attr_set' => ['bool', 'statement'=>'mysqli_stmt', 'attribute'=>'int', 'value'=>'int'], - 'mysqli_stmt_bind_param' => ['bool', 'statement'=>'mysqli_stmt', 'types'=>'string', '&vars'=>'mixed', '&...args='=>'mixed'], + 'mysqli_stmt_bind_param' => ['bool', 'statement'=>'mysqli_stmt', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'], 'mysqli_stmt_bind_result' => ['bool', 'statement'=>'mysqli_stmt', '&w_var1'=>'', '&...w_vars='=>''], 'mysqli_stmt_close' => ['true', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_data_seek' => ['void', 'statement'=>'mysqli_stmt', 'offset'=>'int'], @@ -13008,12 +12979,12 @@ return [ 'nsapi_response_headers' => ['array'], 'nsapi_virtual' => ['bool', 'uri'=>'string'], 'nthmac' => ['string', 'clent'=>'string', 'data'=>'string'], - 'number_format' => ['string', 'num'=>'float|int', 'decimals='=>'int'], - 'number_format\'1' => ['string', 'num'=>'float|int', 'decimals'=>'int', 'decimal_separator'=>'?string', 'thousands_separator'=>'?string'], + 'number_format' => ['string', 'num'=>'float', 'decimals='=>'int'], + 'number_format\'1' => ['string', 'num'=>'float', 'decimals'=>'int', 'decimal_separator'=>'?string', 'thousands_separator'=>'?string'], 'numfmt_create' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], 'numfmt_format' => ['string|false', 'formatter'=>'NumberFormatter', 'num'=>'int|float', 'type='=>'int'], 'numfmt_format_currency' => ['string|false', 'formatter'=>'NumberFormatter', 'amount'=>'float', 'currency'=>'string'], - 'numfmt_get_attribute' => ['int|false', 'formatter'=>'NumberFormatter', 'attribute'=>'int'], + 'numfmt_get_attribute' => ['float|int|false', 'formatter'=>'NumberFormatter', 'attribute'=>'int'], 'numfmt_get_error_code' => ['int', 'formatter'=>'NumberFormatter'], 'numfmt_get_error_message' => ['string', 'formatter'=>'NumberFormatter'], 'numfmt_get_locale' => ['string', 'formatter'=>'NumberFormatter', 'type='=>'int'], @@ -13022,7 +12993,7 @@ return [ 'numfmt_get_text_attribute' => ['string|false', 'formatter'=>'NumberFormatter', 'attribute'=>'int'], 'numfmt_parse' => ['float|int|false', 'formatter'=>'NumberFormatter', 'string'=>'string', 'type='=>'int', '&rw_offset='=>'int'], 'numfmt_parse_currency' => ['float|false', 'formatter'=>'NumberFormatter', 'string'=>'string', '&w_currency'=>'string', '&rw_offset='=>'int'], - 'numfmt_set_attribute' => ['bool', 'formatter'=>'NumberFormatter', 'attribute'=>'int', 'value'=>'int'], + 'numfmt_set_attribute' => ['bool', 'formatter'=>'NumberFormatter', 'attribute'=>'int', 'value'=>'float|int'], 'numfmt_set_pattern' => ['bool', 'formatter'=>'NumberFormatter', 'pattern'=>'string'], 'numfmt_set_symbol' => ['bool', 'formatter'=>'NumberFormatter', 'symbol'=>'int', 'value'=>'string'], 'numfmt_set_text_attribute' => ['bool', 'formatter'=>'NumberFormatter', 'attribute'=>'int', 'value'=>'string'], @@ -13163,9 +13134,9 @@ return [ 'odbc_pconnect' => ['resource|false', 'dsn'=>'string', 'user'=>'string', 'password'=>'string', 'cursor_option='=>'int'], 'odbc_prepare' => ['resource|false', 'odbc'=>'resource', 'query'=>'string'], 'odbc_primarykeys' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string'], - 'odbc_procedurecolumns' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'string', 'schema'=>'string', 'procedure'=>'string', 'column'=>'string'], - 'odbc_procedures' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'string', 'schema'=>'string', 'procedure'=>'string'], - 'odbc_result' => ['mixed|false', 'statement'=>'resource', 'field'=>'mixed'], + 'odbc_procedurecolumns' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'procedure='=>'?string', 'column='=>'?string'], + 'odbc_procedures' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'procedure='=>'?string'], + 'odbc_result' => ['string|bool|null', 'statement'=>'resource', 'field'=>'string|int'], 'odbc_result_all' => ['int|false', 'statement'=>'resource', 'format='=>'string'], 'odbc_rollback' => ['bool', 'odbc'=>'resource'], 'odbc_setoption' => ['bool', 'odbc'=>'resource', 'which'=>'int', 'option'=>'int', 'value'=>'int'], @@ -13229,7 +13200,7 @@ return [ 'openssl_pkcs12_read' => ['bool', 'pkcs12'=>'string', '&w_certificates'=>'array', 'passphrase'=>'string'], 'openssl_pkcs7_decrypt' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'string|resource', 'private_key='=>'string|resource|array'], 'openssl_pkcs7_encrypt' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'string|resource|array', 'headers'=>'array', 'flags='=>'int', 'cipher_algo='=>'int'], - 'openssl_pkcs7_read' => ['bool', 'input_filename'=>'string', '&w_certificates'=>'array'], + 'openssl_pkcs7_read' => ['bool', 'data'=>'string', '&w_certificates'=>'array'], 'openssl_pkcs7_sign' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'string|resource', 'private_key'=>'string|resource|array', 'headers'=>'array', 'flags='=>'int', 'untrusted_certificates_filename='=>'string'], 'openssl_pkcs7_verify' => ['bool|int', 'input_filename'=>'string', 'flags'=>'int', 'signers_certificates_filename='=>'string', 'ca_info='=>'array', 'untrusted_certificates_filename='=>'string', 'content='=>'string', 'output_filename='=>'string'], 'openssl_pkey_export' => ['bool', 'key'=>'resource', '&w_output'=>'string', 'passphrase='=>'string|null', 'options='=>'array'], @@ -13758,7 +13729,7 @@ return [ 'rand\'1' => ['int'], 'random_bytes' => ['non-empty-string', 'length'=>'positive-int'], 'random_int' => ['int', 'min'=>'int', 'max'=>'int'], - 'range' => ['array', 'start'=>'mixed', 'end'=>'mixed', 'step='=>'int|float'], + 'range' => ['non-empty-array', 'start'=>'string|int|float', 'end'=>'string|int|float', 'step='=>'int<1, max>|float'], 'rar_allow_broken_set' => ['bool', 'rarfile'=>'RarArchive', 'allow_broken'=>'bool'], 'rar_broken_is' => ['bool', 'rarfile'=>'rararchive'], 'rar_close' => ['bool', 'rarfile'=>'rararchive'], @@ -13823,7 +13794,7 @@ return [ 'rewind' => ['bool', 'stream'=>'resource'], 'rewinddir' => ['void', 'dir_handle='=>'resource'], 'rmdir' => ['bool', 'directory'=>'string', 'context='=>'resource'], - 'round' => ['float', 'num'=>'float', 'precision='=>'int', 'mode='=>'0|positive-int'], + 'round' => ['float', 'num'=>'float|int', 'precision='=>'int', 'mode='=>'0|positive-int'], 'rpm_close' => ['bool', 'rpmr'=>'resource'], 'rpm_get_tag' => ['mixed', 'rpmr'=>'resource', 'tagnum'=>'int'], 'rpm_is_valid' => ['bool', 'filename'=>'string'], @@ -13907,16 +13878,16 @@ return [ 'sem_remove' => ['bool', 'semaphore'=>'resource'], 'serialize' => ['string', 'value'=>'mixed'], 'session_abort' => ['bool'], - 'session_cache_expire' => ['int', 'value='=>'int'], - 'session_cache_limiter' => ['string', 'value='=>'string'], + 'session_cache_expire' => ['int|false', 'value='=>'int'], + 'session_cache_limiter' => ['string|false', 'value='=>'string'], 'session_commit' => ['bool'], 'session_decode' => ['bool', 'data'=>'string'], 'session_destroy' => ['bool'], - 'session_encode' => ['string'], + 'session_encode' => ['string|false'], 'session_get_cookie_params' => ['array'], 'session_id' => ['string|false', 'id='=>'string'], 'session_is_registered' => ['bool', 'name'=>'string'], - 'session_module_name' => ['string', 'module='=>'string'], + 'session_module_name' => ['string|false', 'module='=>'string'], 'session_name' => ['string|false', 'name='=>'string'], 'session_pgsql_add_error' => ['bool', 'error_level'=>'int', 'error_message='=>'string'], 'session_pgsql_get_error' => ['array', 'with_error_message='=>'bool'], @@ -13928,7 +13899,7 @@ return [ 'session_register' => ['bool', 'name'=>'mixed', '...args='=>'mixed'], 'session_register_shutdown' => ['void'], 'session_reset' => ['bool'], - 'session_save_path' => ['string', 'path='=>'string'], + 'session_save_path' => ['string|false', 'path='=>'string'], 'session_set_cookie_params' => ['bool', 'lifetime'=>'int', 'path='=>'string', 'domain='=>'string', 'secure='=>'bool', 'httponly='=>'bool'], 'session_set_save_handler' => ['bool', 'open'=>'callable(string,string):bool', 'close'=>'callable():bool', 'read'=>'callable(string):string', 'write'=>'callable(string,string):bool', 'destroy'=>'callable(string):bool', 'gc'=>'callable(string):bool', 'create_sid='=>'callable():string', 'validate_sid='=>'callable(string):bool', 'update_timestamp='=>'callable(string):bool'], 'session_set_save_handler\'1' => ['bool', 'open'=>'SessionHandlerInterface', 'close='=>'bool'], @@ -14024,16 +13995,16 @@ return [ 'sinh' => ['float', 'num'=>'float'], 'sizeof' => ['int<0, max>', 'value'=>'Countable|array|SimpleXMLElement', 'mode='=>'int'], 'sleep' => ['int|false', 'seconds'=>'0|positive-int'], - 'snmp2_get' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmp2_getnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmp2_real_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmp2_set' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'type'=>'string', 'value'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmp2_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmp3_get' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmp3_getnext' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmp3_real_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmp3_set' => ['bool', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'string', 'type'=>'string', 'value'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmp3_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], + 'snmp2_get' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmp2_getnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmp2_real_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmp2_set' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'type'=>'array|string', 'value'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmp2_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmp3_get' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmp3_getnext' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmp3_real_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmp3_set' => ['bool', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'type'=>'array|string', 'value'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmp3_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp_get_quick_print' => ['bool'], 'snmp_get_valueretrieval' => ['int'], 'snmp_read_mib' => ['bool', 'filename'=>'string'], @@ -14042,12 +14013,12 @@ return [ 'snmp_set_oid_output_format' => ['true', 'format'=>'int'], 'snmp_set_quick_print' => ['bool', 'enable'=>'bool'], 'snmp_set_valueretrieval' => ['true', 'method'=>'int'], - 'snmpget' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmpgetnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmprealwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmpset' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'type'=>'string|string[]', 'value'=>'string|string[]', 'timeout='=>'int', 'retries='=>'int'], - 'snmpwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], - 'snmpwalkoid' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'string', 'timeout='=>'int', 'retries='=>'int'], + 'snmpget' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmpgetnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmprealwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmpset' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'type'=>'string|string[]', 'value'=>'string|string[]', 'timeout='=>'int', 'retries='=>'int'], + 'snmpwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], + 'snmpwalkoid' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'socket_accept' => ['resource|false', 'socket'=>'resource'], 'socket_bind' => ['bool', 'socket'=>'resource', 'address'=>'string', 'port='=>'int'], 'socket_clear_error' => ['void', 'socket='=>'resource'], @@ -14144,7 +14115,7 @@ return [ 'sqlsrv_commit' => ['bool', 'conn'=>'resource'], 'sqlsrv_configure' => ['bool', 'setting'=>'string', 'value'=>'mixed'], 'sqlsrv_connect' => ['resource|false', 'serverName'=>'string', 'connectionInfo='=>'array'], - 'sqlsrv_errors' => ['?array', 'errorsOrWarnings='=>'int'], + 'sqlsrv_errors' => ['?array', 'errorsAndOrWarnings='=>'int'], 'sqlsrv_execute' => ['bool', 'stmt'=>'resource'], 'sqlsrv_fetch' => ['?bool', 'stmt'=>'resource', 'row='=>'int', 'offset='=>'int'], 'sqlsrv_fetch_array' => ['array|null|false', 'stmt'=>'resource', 'fetchType='=>'int', 'row='=>'int', 'offset='=>'int'], @@ -14340,7 +14311,7 @@ return [ 'stream_context_create' => ['resource', 'options='=>'array', 'params='=>'array'], 'stream_context_get_default' => ['resource', 'options='=>'array'], 'stream_context_get_options' => ['array', 'stream_or_context'=>'resource'], - 'stream_context_get_params' => ['array', 'context'=>'resource'], + 'stream_context_get_params' => ['array{notification:string,options:array}', 'context'=>'resource'], 'stream_context_set_default' => ['resource', 'options'=>'array'], 'stream_context_set_option' => ['bool', 'context'=>'', 'wrapper_or_options'=>'string', 'option_name'=>'string', 'value'=>''], 'stream_context_set_option\'1' => ['bool', 'context'=>'', 'wrapper_or_options'=>'array'], @@ -14370,10 +14341,10 @@ return [ 'stream_socket_accept' => ['resource|false', 'socket'=>'resource', 'timeout='=>'float', '&w_peer_name='=>'string'], 'stream_socket_client' => ['resource|false', 'address'=>'string', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'float', 'flags='=>'int', 'context='=>'resource'], 'stream_socket_enable_crypto' => ['int|bool', 'stream'=>'resource', 'enable'=>'bool', 'crypto_method='=>'?int', 'session_stream='=>'resource'], - 'stream_socket_get_name' => ['string', 'socket'=>'resource', 'remote'=>'bool'], + 'stream_socket_get_name' => ['string|false', 'socket'=>'resource', 'remote'=>'bool'], 'stream_socket_pair' => ['resource[]|false', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int'], - 'stream_socket_recvfrom' => ['string', 'socket'=>'resource', 'length'=>'int', 'flags='=>'int', '&w_address='=>'string'], - 'stream_socket_sendto' => ['int', 'socket'=>'resource', 'data'=>'string', 'flags='=>'int', 'address='=>'string'], + 'stream_socket_recvfrom' => ['string|false', 'socket'=>'resource', 'length'=>'int', 'flags='=>'int', '&w_address='=>'string'], + 'stream_socket_sendto' => ['int|false', 'socket'=>'resource', 'data'=>'string', 'flags='=>'int', 'address='=>'string'], 'stream_socket_server' => ['resource|false', 'address'=>'string', '&w_error_code='=>'int', '&w_error_message='=>'string', 'flags='=>'int', 'context='=>'resource'], 'stream_socket_shutdown' => ['bool', 'stream'=>'resource', 'mode'=>'int'], 'stream_supports_lock' => ['bool', 'stream'=>'resource'], @@ -14808,7 +14779,7 @@ return [ 'symbolObj::setPoints' => ['int', 'double'=>'array'], 'symlink' => ['bool', 'target'=>'string', 'link'=>'string'], 'sys_get_temp_dir' => ['string'], - 'sys_getloadavg' => ['array'], + 'sys_getloadavg' => ['array|false'], 'syslog' => ['true', 'priority'=>'int', 'message'=>'string'], 'system' => ['string|false', 'command'=>'string', '&w_result_code='=>'int'], 'taint' => ['bool', '&rw_string'=>'string', '&...w_other_strings='=>'string'], @@ -15259,7 +15230,7 @@ return [ 'uksort' => ['true', '&rw_array'=>'array', 'callback'=>'callable(mixed,mixed):int'], 'umask' => ['int', 'mask='=>'int'], 'uniqid' => ['non-empty-string', 'prefix='=>'string', 'more_entropy='=>'bool'], - 'unixtojd' => ['int', 'timestamp='=>'int'], + 'unixtojd' => ['int|false', 'timestamp='=>'int'], 'unlink' => ['bool', 'filename'=>'string', 'context='=>'resource'], 'unpack' => ['array', 'format'=>'string', 'string'=>'string'], 'unregister_tick_function' => ['void', 'callback'=>'callable'], @@ -15534,7 +15505,7 @@ return [ 'xml_parser_create' => ['resource', 'encoding='=>'string'], 'xml_parser_create_ns' => ['resource', 'encoding='=>'string', 'separator='=>'string'], 'xml_parser_free' => ['bool', 'parser'=>'resource'], - 'xml_parser_get_option' => ['string|false', 'parser'=>'resource', 'option'=>'int'], + 'xml_parser_get_option' => ['string|int', 'parser'=>'resource', 'option'=>'int'], 'xml_parser_set_option' => ['bool', 'parser'=>'resource', 'option'=>'int', 'value'=>'mixed'], 'xml_set_character_data_handler' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'xml_set_default_handler' => ['true', 'parser'=>'resource', 'handler'=>'callable'], @@ -15689,7 +15660,7 @@ return [ 'zip_entry_compressedsize' => ['int', 'zip_entry'=>'resource'], 'zip_entry_compressionmethod' => ['string', 'zip_entry'=>'resource'], 'zip_entry_filesize' => ['int', 'zip_entry'=>'resource'], - 'zip_entry_name' => ['string', 'zip_entry'=>'resource'], + 'zip_entry_name' => ['string|false', 'zip_entry'=>'resource'], 'zip_entry_open' => ['bool', 'zip_dp'=>'resource', 'zip_entry'=>'resource', 'mode='=>'string'], 'zip_entry_read' => ['string|false', 'zip_entry'=>'resource', 'len='=>'int'], 'zip_open' => ['resource|int|false', 'filename'=>'string'], diff --git a/vendor/vimeo/psalm/docs/annotating_code/supported_annotations.md b/vendor/vimeo/psalm/docs/annotating_code/supported_annotations.md index 922f5baa..346b525f 100644 --- a/vendor/vimeo/psalm/docs/annotating_code/supported_annotations.md +++ b/vendor/vimeo/psalm/docs/annotating_code/supported_annotations.md @@ -7,23 +7,25 @@ Psalm supports a wide range of docblock annotations. Psalm uses the following PHPDoc tags to understand your code: - [`@var`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/var.html) - Used for specifying the types of properties and variables@ + Used for specifying the types of properties and variables - [`@return`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/return.html) Used for specifying the return types of functions, methods and closures - [`@param`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/param.html) Used for specifying types of parameters passed to functions, methods and closures - [`@property`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/property.html) Used to specify what properties can be accessed on an object that uses `__get` and `__set` -- [`@property-read`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/property-read.html) +- [`@property-read`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/property.html) Used to specify what properties can be read on object that uses `__get` -- [`@property-write`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/property-write.html) +- [`@property-write`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/property.html) Used to specify what properties can be written on object that uses `__set` - [`@method`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/method.html) Used to specify which magic methods are available on object that uses `__call`. - [`@deprecated`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/deprecated.html) Used to mark functions, methods, classes and interfaces as being deprecated - [`@internal`](https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/internal.html) - used to mark classes, functions and properties that are internal to an application or library. + Used to mark classes, functions and properties that are internal to an application or library. +- [`@mixin`](#mixins) + Used to tell Psalm that the current class proxies the methods and properties of the referenced class. ### Off-label usage of the `@var` tag @@ -46,6 +48,49 @@ function bat(): string { return $_GET['bat']; } ``` +### @mixins + +Adding `@mixin` to a classes docblock tells Psalm that the class proxies will proxy the methods and properties of the referenced class. + +```php +class A +{ + public string $a = 'A'; + + public function doA(): void + { + } +} + +/** + * @mixin A + */ +class B +{ + public string $b = 'B'; + + public function doB(): void + { + } + + public function __call($name, $arguments) + { + (new A())->$name(...$arguments); + } + + public function __get($name) + { + (new A())->$name; + } +} + +$b = new B(); +$b->doB(); +$b->doA(); // works +echo $b->b; +echo $b->a; // works +``` + ## Psalm-specific tags @@ -157,9 +202,10 @@ takesFoo(getFoo()); This provides the same, but for `false`. Psalm uses this internally for functions like `preg_replace`, which can return false if the given input has encoding errors, but where 99.9% of the time the function operates as expected. -### `@psalm-seal-properties` +### `@psalm-seal-properties`, `@psalm-no-seal-properties` If you have a magic property getter/setter, you can use `@psalm-seal-properties` to instruct Psalm to disallow getting and setting any properties not contained in a list of `@property` (or `@property-read`/`@property-write`) annotations. +This is automatically enabled with the configuration option `sealAllProperties` and can be disabled for a class with `@psalm-no-seal-properties` ```php bar = 5; // this call fails ``` +### `@psalm-seal-methods`, `@psalm-no-seal-methods` + +If you have a magic method caller, you can use `@psalm-seal-methods` to instruct Psalm to disallow calling any methods not contained in a list of `@method` annotations. +This is automatically enabled with the configuration option `sealAllMethods` and can be disabled for a class with `@psalm-no-seal-methods` + +```php +bar(); // this call fails +``` + ### `@psalm-internal` Used to mark a class, property or function as internal to a given namespace. Psalm treats this slightly differently to @@ -446,7 +515,18 @@ $username = $_GET['username']; // prints something like "test.php:4 $username: m ``` -*Note*: it throws [special low-level issue](../running_psalm/issues/Trace.md), so you have to set errorLevel to 1, override it in config or invoke Psalm with `--show-info=true`. +*Note*: it throws [special low-level issue](../running_psalm/issues/Trace.md). +To see it, you can set the global `errorLevel` to 1, or invoke Psalm with +`--show-info=true`, but both these solutions will probably result in a lot of +output. Another solution is to selectively bump the error level of the issue, +so that you only get one more error: + +```xml + + + + +``` ### `@psalm-check-type` @@ -596,7 +676,7 @@ class Foo } ``` When Psalm encounters variable property, it treats all properties in given class as potentially referenced. -With `@psalm-ignore-variable-property` annotation, this reference is ignored. +With `@psalm-ignore-variable-property` annotation, this reference is ignored. While `PossiblyUnusedProperty` would be emitted in both cases, using `@psalm-ignore-variable-property` would allow [Psalter](../manipulating_code/fixing.md) to delete `Foo::$bar`. @@ -642,9 +722,9 @@ function (): Generator { ``` This annotation supports only generic types, meaning that e.g. `@psalm-yield string` would be ignored. -### `@psalm-api` +### `@api`, `@psalm-api` -Used to tell Psalm that a class is used, even if no references to it can be +Used to tell Psalm that a class or method is used, even if no references to it can be found. Unused issues will be suppressed. For example, in frameworks, controllers are often invoked "magically" without @@ -657,6 +737,22 @@ any explicit references to them in your code. You should mark these classes with class UnreferencedClass {} ``` +### `@psalm-inheritors` + +Used to tell Psalm that a class can only be extended by a certain subset of classes. + +For example, +```php +` you can use other array generic types to provide more information about the open shape. + +```php +// This is an open array +/** @param array{someKey: string, ...} */ +// Which is the same as +/** @param array{someKey: string, ...} */ +// But it can be further locked down with a shape ... +/** @return array{someKey: string, ...} */ +``` + ## Callable arrays An array holding a callable, like PHP's native `call_user_func()` and friends supports it: diff --git a/vendor/vimeo/psalm/docs/annotating_code/type_syntax/atomic_types.md b/vendor/vimeo/psalm/docs/annotating_code/type_syntax/atomic_types.md index 7e3f0ea9..612cf9f7 100644 --- a/vendor/vimeo/psalm/docs/annotating_code/type_syntax/atomic_types.md +++ b/vendor/vimeo/psalm/docs/annotating_code/type_syntax/atomic_types.md @@ -46,7 +46,7 @@ Atomic types are the basic building block of all type information used in Psalm. * [`key-of`](utility_types.md#key-oft) * [`value-of`](utility_types.md#value-oft) * [`properties-of`](utility_types.md#properties-oft) - * [`class-string-map`](utility_types.md#class-string-mapt-as-foo-t) + * [`class-string-map`](utility_types.md#class-string-mapt-as-foo-t) * [`T[K]`](utility_types.md#tk) * [Type aliases](utility_types.md#type-aliases) * [Variable templates](utility_types.md#variable-templates) diff --git a/vendor/vimeo/psalm/docs/annotating_code/type_syntax/utility_types.md b/vendor/vimeo/psalm/docs/annotating_code/type_syntax/utility_types.md index d2de471f..4e690cbd 100644 --- a/vendor/vimeo/psalm/docs/annotating_code/type_syntax/utility_types.md +++ b/vendor/vimeo/psalm/docs/annotating_code/type_syntax/utility_types.md @@ -148,7 +148,7 @@ $b = asArray(new B); /** @psalm-trace $b */; // array{foo: string, bar: int, baz: float} ``` -## class-string-map<T as Foo, T> +## class-string-map<T of Foo, T> Used to indicate an array where each value is equal an instance of the class string contained in the key: @@ -166,11 +166,11 @@ class Foo {} class Bar extends Foo {} class A { - /** @var class-string-map */ + /** @var class-string-map */ private static array $map = []; /** - * @template U as Foo + * @template U of Foo * @param class-string $class * @return U */ @@ -191,7 +191,7 @@ $bar = A::get(Bar::class); /** @psalm-trace $bar */; // Bar ``` -If we had used an `array, Foo>` instead of a `class-string-map` in the above example, we would've gotten some false positive `InvalidReturnStatement` issues, caused by the lack of a type assertion inside the `isset`. +If we had used an `array, Foo>` instead of a `class-string-map` in the above example, we would've gotten some false positive `InvalidReturnStatement` issues, caused by the lack of a type assertion inside the `isset`. On the other hand, when using `class-string-map`, Psalm assumes that the value obtained by using a key `class-string` is always equal to `T`. Unbounded templates can also be used for unrelated classes: @@ -250,8 +250,8 @@ Used to get the value corresponding to the specified key: +``` +Whether using @property in class docblocks should imply @psalm-seal-properties. Defaults to `true`. + #### usePhpDocMethodsWithoutMagicCall ```xml diff --git a/vendor/vimeo/psalm/docs/running_psalm/issues.md b/vendor/vimeo/psalm/docs/running_psalm/issues.md index 9eb35fce..d9b3b4f1 100644 --- a/vendor/vimeo/psalm/docs/running_psalm/issues.md +++ b/vendor/vimeo/psalm/docs/running_psalm/issues.md @@ -52,6 +52,7 @@ - [InaccessibleClassConstant](issues/InaccessibleClassConstant.md) - [InaccessibleMethod](issues/InaccessibleMethod.md) - [InaccessibleProperty](issues/InaccessibleProperty.md) + - [InheritorViolation](issues/InheritorViolation.md) - [InterfaceInstantiation](issues/InterfaceInstantiation.md) - [InternalClass](issues/InternalClass.md) - [InternalMethod](issues/InternalMethod.md) @@ -284,6 +285,7 @@ - [UnresolvableInclude](issues/UnresolvableInclude.md) - [UnsafeGenericInstantiation](issues/UnsafeGenericInstantiation.md) - [UnsafeInstantiation](issues/UnsafeInstantiation.md) + - [UnsupportedPropertyReferenceUsage](issues/UnsupportedPropertyReferenceUsage.md) - [UnsupportedReferenceUsage](issues/UnsupportedReferenceUsage.md) - [UnusedBaselineEntry](issues/UnusedBaselineEntry.md) - [UnusedClass](issues/UnusedClass.md) diff --git a/vendor/vimeo/psalm/docs/running_psalm/issues/InheritorViolation.md b/vendor/vimeo/psalm/docs/running_psalm/issues/InheritorViolation.md new file mode 100644 index 00000000..33b9ffef --- /dev/null +++ b/vendor/vimeo/psalm/docs/running_psalm/issues/InheritorViolation.md @@ -0,0 +1,17 @@ +# InheritorViolation + +Emitted when a class/interface using `@psalm-inheritors` is extended/implemented +by a class that does not fulfil it's requirements. + +```php +b; +$b = ''; // Fatal error +``` + +* Static property assigned wrong type: +```php +b; +$b = 1; // Fatal error +``` diff --git a/vendor/vimeo/psalm/docs/security_analysis/avoiding_false_positives.md b/vendor/vimeo/psalm/docs/security_analysis/avoiding_false_positives.md index 13023660..583d8f33 100644 --- a/vendor/vimeo/psalm/docs/security_analysis/avoiding_false_positives.md +++ b/vendor/vimeo/psalm/docs/security_analysis/avoiding_false_positives.md @@ -26,7 +26,7 @@ function echoVar(string $str) : void { echoVar($_GET["text"]); ``` -## Conditional escaping tainted input +## Conditionally escaping tainted input A slightly modified version of the previous example is using a condition to determine whether the return value is considered secure. Only in case function argument `$escape` is true, the corresponding annotation @@ -50,6 +50,23 @@ echo processVar($_GET['text'], false); // detects tainted HTML echo processVar($_GET['text'], true); // considered secure ``` +## Sanitizing HTML user input + +Whenever possible, applications should be designed to accept & store user input as discrete text fields, rather than blocks of HTML. This allows user input to be fully escaped via `htmlspecialchars` or `htmlentities`. In cases where HTML user input is required (e.g. rich text editors like [TinyMCE](https://www.tiny.cloud/)), a library designed specifically to filter out risky HTML is highly recommended. For example, [HTML Purifier](http://htmlpurifier.org/docs) could be used as follows: + +```php +purify($html); +} +``` + ## Specializing taints in functions For functions, methods and classes you can use the `@psalm-taint-specialize` annotation. diff --git a/vendor/vimeo/psalm/src/Psalm/CodeLocation.php b/vendor/vimeo/psalm/src/Psalm/CodeLocation.php index 04790dfc..0bdfd64a 100644 --- a/vendor/vimeo/psalm/src/Psalm/CodeLocation.php +++ b/vendor/vimeo/psalm/src/Psalm/CodeLocation.php @@ -169,6 +169,7 @@ class CodeLocation $codebase = $project_analyzer->getCodebase(); + /** @psalm-suppress ImpureMethodCall */ $file_contents = $codebase->getFileContents($this->file_path); $file_length = strlen($file_contents); diff --git a/vendor/vimeo/psalm/src/Psalm/Codebase.php b/vendor/vimeo/psalm/src/Psalm/Codebase.php index 2e51cd49..d6caa46d 100644 --- a/vendor/vimeo/psalm/src/Psalm/Codebase.php +++ b/vendor/vimeo/psalm/src/Psalm/Codebase.php @@ -37,6 +37,8 @@ use Psalm\Internal\Codebase\Scanner; use Psalm\Internal\Codebase\TaintFlowGraph; use Psalm\Internal\DataFlow\TaintSink; use Psalm\Internal\DataFlow\TaintSource; +use Psalm\Internal\LanguageServer\PHPMarkdownContent; +use Psalm\Internal\LanguageServer\Reference; use Psalm\Internal\MethodIdentifier; use Psalm\Internal\Provider\ClassLikeStorageProvider; use Psalm\Internal\Provider\FileProvider; @@ -67,8 +69,10 @@ use ReflectionType; use UnexpectedValueException; use function array_combine; +use function array_merge; use function array_pop; use function array_reverse; +use function array_values; use function count; use function dirname; use function error_log; @@ -82,6 +86,7 @@ use function krsort; use function ksort; use function preg_match; use function preg_replace; +use function str_replace; use function strlen; use function strpos; use function strrpos; @@ -390,15 +395,19 @@ final class Codebase /** * @param array $candidate_files */ - public function reloadFiles(ProjectAnalyzer $project_analyzer, array $candidate_files): void + public function reloadFiles(ProjectAnalyzer $project_analyzer, array $candidate_files, bool $force = false): void { $this->loadAnalyzer(); + if ($force) { + FileReferenceProvider::clearCache(); + } + $this->file_reference_provider->loadReferenceCache(false); FunctionLikeAnalyzer::clearCache(); - if (!$this->statements_provider->parser_cache_provider) { + if ($force || !$this->statements_provider->parser_cache_provider) { $diff_files = $candidate_files; } else { $diff_files = []; @@ -500,7 +509,6 @@ final class Codebase } } - /** @psalm-mutation-free */ public function getFileContents(string $file_path): string { return $this->file_provider->getContents($file_path); @@ -593,6 +601,7 @@ final class Codebase */ public function findReferencesToProperty(string $property_id): array { + /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ [$fq_class_name, $property_name] = explode('::', $property_id); return $this->file_reference_provider->getClassPropertyLocations( @@ -970,7 +979,225 @@ final class Codebase } /** - * @return array{ type: string, description?: string|null}|null + * Get Markup content from Reference + */ + public function getMarkupContentForSymbolByReference( + Reference $reference + ): ?PHPMarkdownContent { + //Direct Assignment + if (is_numeric($reference->symbol[0])) { + return new PHPMarkdownContent( + preg_replace( + '/^[^:]*:/', + '', + $reference->symbol, + ), + ); + } + + //Class + if (strpos($reference->symbol, '::')) { + //Class Method + if (strpos($reference->symbol, '()')) { + $symbol = substr($reference->symbol, 0, -2); + + /** @psalm-suppress ArgumentTypeCoercion */ + $method_id = new MethodIdentifier(...explode('::', $symbol)); + + $declaring_method_id = $this->methods->getDeclaringMethodId( + $method_id, + ); + + if (!$declaring_method_id) { + return null; + } + + $storage = $this->methods->getStorage($declaring_method_id); + + return new PHPMarkdownContent( + $storage->getHoverMarkdown(), + "{$storage->defining_fqcln}::{$storage->cased_name}", + $storage->description, + ); + } + + /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ + [, $symbol_name] = explode('::', $reference->symbol); + + //Class Property + if (strpos($reference->symbol, '$') !== false) { + $property_id = preg_replace('/^\\\\/', '', $reference->symbol); + /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ + [$fq_class_name, $property_name] = explode('::$', $property_id); + $class_storage = $this->classlikes->getStorageFor($fq_class_name); + + //Get Real Properties + if (isset($class_storage->declaring_property_ids[$property_name])) { + $declaring_property_class = $class_storage->declaring_property_ids[$property_name]; + $declaring_class_storage = $this->classlike_storage_provider->get($declaring_property_class); + + if (isset($declaring_class_storage->properties[$property_name])) { + $storage = $declaring_class_storage->properties[$property_name]; + return new PHPMarkdownContent( + "{$storage->getInfo()} {$symbol_name}", + $reference->symbol, + $storage->description, + ); + } + } + + //Get Docblock properties + if (isset($class_storage->pseudo_property_set_types['$'.$property_name])) { + return new PHPMarkdownContent( + 'public '. + (string) $class_storage->pseudo_property_set_types['$'.$property_name].' $'.$property_name, + $reference->symbol, + ); + } + + //Get Docblock properties + if (isset($class_storage->pseudo_property_get_types['$'.$property_name])) { + return new PHPMarkdownContent( + 'public '. + (string) $class_storage->pseudo_property_get_types['$'.$property_name].' $'.$property_name, + $reference->symbol, + ); + } + + return null; + } + + /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ + [$fq_classlike_name, $const_name] = explode( + '::', + $reference->symbol, + ); + + $class_constants = $this->classlikes->getConstantsForClass( + $fq_classlike_name, + ReflectionProperty::IS_PRIVATE, + ); + + if (!isset($class_constants[$const_name])) { + return null; + } + + //Class Constant + return new PHPMarkdownContent( + $class_constants[$const_name]->getHoverMarkdown($const_name), + $fq_classlike_name . '::' . $const_name, + $class_constants[$const_name]->description, + ); + } + + //Procedural Function + if (strpos($reference->symbol, '()')) { + $function_id = strtolower(substr($reference->symbol, 0, -2)); + $file_storage = $this->file_storage_provider->get( + $reference->file_path, + ); + + if (isset($file_storage->functions[$function_id])) { + $function_storage = $file_storage->functions[$function_id]; + + return new PHPMarkdownContent( + $function_storage->getHoverMarkdown(), + $function_id, + $function_storage->description, + ); + } + + if (!$function_id) { + return null; + } + + $function = $this->functions->getStorage(null, $function_id); + + return new PHPMarkdownContent( + $function->getHoverMarkdown(), + $function_id, + $function->description, + ); + } + + //Procedural Variable + if (strpos($reference->symbol, '$') === 0) { + $type = VariableFetchAnalyzer::getGlobalType($reference->symbol, $this->analysis_php_version_id); + if (!$type->isMixed()) { + return new PHPMarkdownContent( + (string) $type, + $reference->symbol, + ); + } + } + + try { + $storage = $this->classlike_storage_provider->get( + $reference->symbol, + ); + return new PHPMarkdownContent( + ($storage->abstract ? 'abstract ' : '') . + 'class ' . + $storage->name, + $storage->name, + $storage->description, + ); + } catch (InvalidArgumentException $e) { + //continue on as normal + } + + if (strpos($reference->symbol, '\\')) { + $const_name_parts = explode('\\', $reference->symbol); + $const_name = array_pop($const_name_parts); + $namespace_name = implode('\\', $const_name_parts); + + $namespace_constants = NamespaceAnalyzer::getConstantsForNamespace( + $namespace_name, + ReflectionProperty::IS_PUBLIC, + ); + //Namespace Constant + if (isset($namespace_constants[$const_name])) { + $type = $namespace_constants[$const_name]; + return new PHPMarkdownContent( + $reference->symbol . ' ' . $type, + $reference->symbol, + ); + } + } else { + $file_storage = $this->file_storage_provider->get( + $reference->file_path, + ); + // ? + if (isset($file_storage->constants[$reference->symbol])) { + return new PHPMarkdownContent( + 'const ' . + $reference->symbol . + ' ' . + $file_storage->constants[$reference->symbol], + $reference->symbol, + ); + } + $type = ConstFetchAnalyzer::getGlobalConstType( + $this, + $reference->symbol, + $reference->symbol, + ); + + //Global Constant + if ($type) { + return new PHPMarkdownContent( + 'const ' . $reference->symbol . ' ' . $type, + $reference->symbol, + ); + } + } + + return new PHPMarkdownContent($reference->symbol); + } + + /** + * @psalm-suppress PossiblyUnusedMethod + * @deprecated will be removed in Psalm 6. use {@see Codebase::getSymbolLocationByReference()} instead */ public function getSymbolInformation(string $file_path, string $symbol): ?array { @@ -995,7 +1222,7 @@ final class Codebase $storage = $this->methods->getStorage($declaring_method_id); return [ - 'type' => 'getSignature(true), + 'type' => 'getCompletionSignature(), 'description' => $storage->description, ]; } @@ -1036,7 +1263,7 @@ final class Codebase $function_storage = $file_storage->functions[$function_id]; return [ - 'type' => 'getSignature(true), + 'type' => 'getCompletionSignature(), 'description' => $function_storage->description, ]; } @@ -1047,7 +1274,7 @@ final class Codebase $function = $this->functions->getStorage(null, $function_id); return [ - 'type' => 'getSignature(true), + 'type' => 'getCompletionSignature(), 'description' => $function->description, ]; } @@ -1100,6 +1327,10 @@ final class Codebase } } + /** + * @psalm-suppress PossiblyUnusedMethod + * @deprecated will be removed in Psalm 6. use {@see Codebase::getSymbolLocationByReference()} instead + */ public function getSymbolLocation(string $file_path, string $symbol): ?CodeLocation { if (is_numeric($symbol[0])) { @@ -1182,11 +1413,127 @@ final class Codebase } } + public function getSymbolLocationByReference(Reference $reference): ?CodeLocation + { + if (is_numeric($reference->symbol[0])) { + $symbol = preg_replace('/:.*/', '', $reference->symbol); + $symbol_parts = explode('-', $symbol); + + if (!isset($symbol_parts[0]) || !isset($symbol_parts[1])) { + return null; + } + + $file_contents = $this->getFileContents($reference->file_path); + + return new Raw( + $file_contents, + $reference->file_path, + $this->config->shortenFileName($reference->file_path), + (int) $symbol_parts[0], + (int) $symbol_parts[1], + ); + } + + try { + if (strpos($reference->symbol, '::')) { + if (strpos($reference->symbol, '()')) { + $symbol = substr($reference->symbol, 0, -2); + + /** @psalm-suppress ArgumentTypeCoercion */ + $method_id = new MethodIdentifier( + ...explode('::', $symbol), + ); + + $declaring_method_id = $this->methods->getDeclaringMethodId( + $method_id, + ); + + if (!$declaring_method_id) { + return null; + } + + $storage = $this->methods->getStorage($declaring_method_id); + + return $storage->location; + } + + if (strpos($reference->symbol, '$') !== false) { + $storage = $this->properties->getStorage( + $reference->symbol, + ); + + return $storage->location; + } + + /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ + [$fq_classlike_name, $const_name] = explode( + '::', + $reference->symbol, + ); + + $class_constants = $this->classlikes->getConstantsForClass( + $fq_classlike_name, + ReflectionProperty::IS_PRIVATE, + ); + + if (!isset($class_constants[$const_name])) { + return null; + } + + return $class_constants[$const_name]->location; + } + + if (strpos($reference->symbol, '()')) { + $file_storage = $this->file_storage_provider->get( + $reference->file_path, + ); + + $function_id = strtolower(substr($reference->symbol, 0, -2)); + + if (isset($file_storage->functions[$function_id])) { + return $file_storage->functions[$function_id]->location; + } + + if (!$function_id) { + return null; + } + + return $this->functions->getStorage(null, $function_id) + ->location; + } + + return $this->classlike_storage_provider->get( + $reference->symbol, + )->location; + } catch (UnexpectedValueException $e) { + error_log($e->getMessage()); + + return null; + } catch (InvalidArgumentException $e) { + return null; + } + } + /** + * @psalm-suppress PossiblyUnusedMethod * @return array{0: string, 1: Range}|null */ public function getReferenceAtPosition(string $file_path, Position $position): ?array { + $ref = $this->getReferenceAtPositionAsReference($file_path, $position); + if ($ref === null) { + return null; + } + return [$ref->symbol, $ref->range]; + } + + /** + * Get Reference from Position + */ + public function getReferenceAtPositionAsReference( + string $file_path, + Position $position + ): ?Reference { $is_open = $this->file_provider->isOpen($file_path); if (!$is_open) { @@ -1197,33 +1544,37 @@ final class Codebase $offset = $position->toOffset($file_contents); - [$reference_map, $type_map] = $this->analyzer->getMapsForFile($file_path); - - $reference = null; - - if (!$reference_map && !$type_map) { - return null; - } + $reference_maps = $this->analyzer->getMapsForFile($file_path); $reference_start_pos = null; $reference_end_pos = null; + $symbol = null; - ksort($reference_map); + foreach ($reference_maps as $reference_map) { + ksort($reference_map); - foreach ($reference_map as $start_pos => [$end_pos, $possible_reference]) { - if ($offset < $start_pos) { + foreach ($reference_map as $start_pos => [$end_pos, $possible_reference]) { + if ($offset < $start_pos) { + break; + } + + if ($offset > $end_pos) { + continue; + } + $reference_start_pos = $start_pos; + $reference_end_pos = $end_pos; + $symbol = $possible_reference; + } + + if ($symbol !== null && + $reference_start_pos !== null && + $reference_end_pos !== null + ) { break; } - - if ($offset > $end_pos) { - continue; - } - $reference_start_pos = $start_pos; - $reference_end_pos = $end_pos; - $reference = $possible_reference; } - if ($reference === null || $reference_start_pos === null || $reference_end_pos === null) { + if ($symbol === null || $reference_start_pos === null || $reference_end_pos === null) { return null; } @@ -1232,7 +1583,7 @@ final class Codebase self::getPositionFromOffset($reference_end_pos, $file_contents), ); - return [$reference, $range]; + return new Reference($file_path, $symbol, $range); } /** @@ -1399,6 +1750,7 @@ final class Codebase continue; } + /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ $num_whitespace_bytes = preg_match('/\G\s+/', $file_contents, $matches, 0, $end_pos_excluding_whitespace) ? strlen($matches[0]) : 0; @@ -1487,8 +1839,11 @@ final class Codebase /** * @return list */ - public function getCompletionItemsForClassishThing(string $type_string, string $gap): array - { + public function getCompletionItemsForClassishThing( + string $type_string, + string $gap, + bool $snippets_supported = false + ): array { $completion_items = []; $type = Type::parseString($type_string); @@ -1505,11 +1860,11 @@ final class Codebase $completion_item = new CompletionItem( $method_storage->cased_name, CompletionItemKind::METHOD, - (string)$method_storage, + $method_storage->getCompletionSignature(), $method_storage->description, (string)$method_storage->visibility, $method_storage->cased_name, - $method_storage->cased_name . (count($method_storage->params) !== 0 ? '($0)' : '()'), + $method_storage->cased_name, null, null, new Command('Trigger parameter hints', 'editor.action.triggerParameterHints'), @@ -1517,12 +1872,47 @@ final class Codebase 2, ); - $completion_item->insertTextFormat = InsertTextFormat::SNIPPET; + if ($snippets_supported && count($method_storage->params) > 0) { + $completion_item->insertText .= '($0)'; + $completion_item->insertTextFormat = + InsertTextFormat::SNIPPET; + } else { + $completion_item->insertText .= '()'; + } $completion_items[] = $completion_item; } } + $pseudo_property_types = []; + foreach ($class_storage->pseudo_property_get_types as $property_name => $type) { + $pseudo_property_types[$property_name] = new CompletionItem( + str_replace('$', '', $property_name), + CompletionItemKind::PROPERTY, + $type->__toString(), + null, + '1', //sort text + str_replace('$', '', $property_name), + ($gap === '::' ? '$' : '') . + str_replace('$', '', $property_name), + ); + } + + foreach ($class_storage->pseudo_property_set_types as $property_name => $type) { + $pseudo_property_types[$property_name] = new CompletionItem( + str_replace('$', '', $property_name), + CompletionItemKind::PROPERTY, + $type->__toString(), + null, + '1', + str_replace('$', '', $property_name), + ($gap === '::' ? '$' : '') . + str_replace('$', '', $property_name), + ); + } + + $completion_items = array_merge($completion_items, array_values($pseudo_property_types)); + foreach ($class_storage->declaring_property_ids as $property_name => $declaring_class) { $property_storage = $this->properties->getStorage( $declaring_class . '::$' . $property_name, @@ -1715,7 +2105,7 @@ final class Codebase $completion_items[] = new CompletionItem( $function_name, CompletionItemKind::FUNCTION, - $function->getSignature(false), + $function->getCompletionSignature(), $function->description, null, $function_name, @@ -1832,9 +2222,9 @@ final class Codebase ); } - public function addTemporaryFileChanges(string $file_path, string $new_content): void + public function addTemporaryFileChanges(string $file_path, string $new_content, ?int $version = null): void { - $this->file_provider->addTemporaryFileChanges($file_path, $new_content); + $this->file_provider->addTemporaryFileChanges($file_path, $new_content, $version); } public function removeTemporaryFileChanges(string $file_path): void diff --git a/vendor/vimeo/psalm/src/Psalm/Config.php b/vendor/vimeo/psalm/src/Psalm/Config.php index de71b0d1..fcc1fbea 100644 --- a/vendor/vimeo/psalm/src/Psalm/Config.php +++ b/vendor/vimeo/psalm/src/Psalm/Config.php @@ -194,6 +194,13 @@ class Config */ public $use_docblock_property_types = false; + /** + * Whether using property annotations in docblocks should implicitly seal properties + * + * @var bool + */ + public $docblock_property_types_seal_properties = true; + /** * Whether or not to throw an exception on first error * @@ -1049,6 +1056,7 @@ class Config $booleanAttributes = [ 'useDocblockTypes' => 'use_docblock_types', 'useDocblockPropertyTypes' => 'use_docblock_property_types', + 'docblockPropertyTypesSealProperties' => 'docblock_property_types_seal_properties', 'throwExceptionOnError' => 'throw_exception', 'hideExternalErrors' => 'hide_external_errors', 'hideAllErrorsExceptPassedFiles' => 'hide_all_errors_except_passed_files', @@ -1727,7 +1735,8 @@ class Config public function reportIssueInFile(string $issue_type, string $file_path): bool { - if (($this->show_mixed_issues === false || $this->level > 2) + if ((($this->level < 3 && $this->show_mixed_issues === false) + || ($this->level > 2 && $this->show_mixed_issues !== true)) && in_array($issue_type, self::MIXED_ISSUES, true) ) { return false; diff --git a/vendor/vimeo/psalm/src/Psalm/Config/FileFilter.php b/vendor/vimeo/psalm/src/Psalm/Config/FileFilter.php index 01b1656e..cefa55b0 100644 --- a/vendor/vimeo/psalm/src/Psalm/Config/FileFilter.php +++ b/vendor/vimeo/psalm/src/Psalm/Config/FileFilter.php @@ -122,6 +122,7 @@ class FileFilter $declare_strict_types = (bool) ($directory['useStrictTypes'] ?? false); if ($directory_path[0] === '/' && DIRECTORY_SEPARATOR === '/') { + /** @var non-empty-string */ $prospective_directory_path = $directory_path; } else { $prospective_directory_path = $base_dir . DIRECTORY_SEPARATOR . $directory_path; @@ -238,6 +239,7 @@ class FileFilter $file_path = (string) ($file['name'] ?? ''); if ($file_path[0] === '/' && DIRECTORY_SEPARATOR === '/') { + /** @var non-empty-string */ $prospective_file_path = $file_path; } else { $prospective_file_path = $base_dir . DIRECTORY_SEPARATOR . $file_path; diff --git a/vendor/vimeo/psalm/src/Psalm/DocComment.php b/vendor/vimeo/psalm/src/Psalm/DocComment.php index 3c4d09ad..2a04279f 100644 --- a/vendor/vimeo/psalm/src/Psalm/DocComment.php +++ b/vendor/vimeo/psalm/src/Psalm/DocComment.php @@ -24,6 +24,7 @@ final class DocComment 'assert', 'assert-if-true', 'assert-if-false', 'suppress', 'ignore-nullable-return', 'override-property-visibility', 'override-method-visibility', 'seal-properties', 'seal-methods', + 'no-seal-properties', 'no-seal-methods', 'ignore-falsable-return', 'variadic', 'pure', 'ignore-variable-method', 'ignore-variable-property', 'internal', 'taint-sink', 'taint-source', 'assert-untainted', 'scope-this', @@ -33,7 +34,7 @@ final class DocComment 'taint-unescape', 'self-out', 'consistent-constructor', 'stub-override', 'require-extends', 'require-implements', 'param-out', 'ignore-var', 'consistent-templates', 'if-this-is', 'this-out', 'check-type', 'check-type-exact', - 'api', + 'api', 'inheritors', ]; /** diff --git a/vendor/vimeo/psalm/src/Psalm/ErrorBaseline.php b/vendor/vimeo/psalm/src/Psalm/ErrorBaseline.php index 9a22ec82..9a83b0a2 100644 --- a/vendor/vimeo/psalm/src/Psalm/ErrorBaseline.php +++ b/vendor/vimeo/psalm/src/Psalm/ErrorBaseline.php @@ -118,7 +118,7 @@ final class ErrorBaseline foreach ($codeSamples as $codeSample) { $files[$fileName][$issueType]['o'] += 1; - $files[$fileName][$issueType]['s'][] = trim($codeSample->textContent); + $files[$fileName][$issueType]['s'][] = str_replace("\r\n", "\n", trim($codeSample->textContent)); } // TODO: Remove in Psalm 6 diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php index 137b4755..3d120c89 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php @@ -362,16 +362,6 @@ class ClassAnalyzer extends ClassLikeAnalyzer return; } - if ($this->leftover_stmts) { - (new StatementsAnalyzer( - $this, - new NodeDataProvider(), - ))->analyze( - $this->leftover_stmts, - $class_context, - ); - } - if (!$storage->abstract) { foreach ($storage->declaring_method_ids as $declaring_method_id) { $method_storage = $codebase->methods->getStorage($declaring_method_id); @@ -712,7 +702,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer new OverriddenPropertyAccess( 'Property ' . $fq_class_name . '::$' . $property_name . ' has different access level than ' - . $storage->name . '::$' . $property_name, + . $guide_class_name . '::$' . $property_name, $property_storage->location, ), ); @@ -1781,8 +1771,6 @@ class ClassAnalyzer extends ClassLikeAnalyzer $method_context = clone $class_context; foreach ($method_context->vars_in_scope as $context_var_id => $context_type) { - $method_context->vars_in_scope[$context_var_id] = $context_type; - if ($context_type->from_property && $stmt->name->name !== '__construct') { $method_context->vars_in_scope[$context_var_id] = $method_context->vars_in_scope[$context_var_id]->setProperties(['initialized' => true]); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php index 60491a78..92e86998 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php @@ -14,6 +14,7 @@ use Psalm\Internal\Type\Comparator\UnionTypeComparator; use Psalm\Internal\Type\TemplateResult; use Psalm\Internal\Type\TemplateStandinTypeReplacer; use Psalm\Issue\InaccessibleProperty; +use Psalm\Issue\InheritorViolation; use Psalm\Issue\InvalidClass; use Psalm\Issue\InvalidTemplateParam; use Psalm\Issue\MissingDependency; @@ -28,6 +29,7 @@ use Psalm\Plugin\EventHandler\Event\AfterClassLikeExistenceCheckEvent; use Psalm\StatementsSource; use Psalm\Storage\ClassLikeStorage; use Psalm\Type; +use Psalm\Type\Atomic\TNamedObject; use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Union; use UnexpectedValueException; @@ -92,11 +94,6 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer */ protected ?string $parent_fq_class_name = null; - /** - * @var PhpParser\Node\Stmt[] - */ - protected array $leftover_stmts = []; - protected ClassLikeStorage $storage; public function __construct(PhpParser\Node\Stmt\ClassLike $class, SourceAnalyzer $source, string $fq_class_name) @@ -336,6 +333,23 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer return null; } + + $classUnion = new Union([new TNamedObject($fq_class_name)]); + foreach ($class_storage->parent_classes + $class_storage->direct_class_interfaces as $parent_class) { + $parent_storage = $codebase->classlikes->getStorageFor($parent_class); + if ($parent_storage && $parent_storage->inheritors) { + if (!UnionTypeComparator::isContainedBy($codebase, $classUnion, $parent_storage->inheritors)) { + IssueBuffer::maybeAdd( + new InheritorViolation( + 'Class ' . $fq_class_name . ' is not an allowed inheritor of parent class ' . $parent_class, + $code_location, + ), + $suppressed_issues, + ); + } + } + } + foreach ($class_storage->invalid_dependencies as $dependency_class_name => $_) { // if the implemented/extended class is stubbed, it may not yet have // been hydrated diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php index 152565c2..3c0b6f2b 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php @@ -72,6 +72,7 @@ use function count; use function end; use function in_array; use function is_string; +use function krsort; use function mb_strpos; use function md5; use function microtime; @@ -80,6 +81,8 @@ use function strpos; use function strtolower; use function substr; +use const SORT_NUMERIC; + /** * @internal * @template-covariant TFunction as Closure|Function_|ClassMethod|ArrowFunction @@ -721,7 +724,10 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer if ($expected_exception === $possibly_thrown_exception || ( $codebase->classOrInterfaceExists($possibly_thrown_exception) - && $codebase->classExtendsOrImplements($possibly_thrown_exception, $expected_exception) + && ( + $codebase->interfaceExtends($possibly_thrown_exception, $expected_exception) + || $codebase->classExtendsOrImplements($possibly_thrown_exception, $expected_exception) + ) ) ) { $is_expected = true; @@ -870,96 +876,55 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer ): void { $codebase = $statements_analyzer->getCodebase(); - $unused_params = []; + $unused_params = $this->detectUnusedParameters($statements_analyzer, $storage, $context); - foreach ($statements_analyzer->getUnusedVarLocations() as [$var_name, $original_location]) { - if (!array_key_exists(substr($var_name, 1), $storage->param_lookup)) { - continue; - } + if (!$storage instanceof MethodStorage + || !$storage->cased_name + || $storage->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE + ) { + $last_unused_argument_position = $this->detectPreviousUnusedArgumentPosition( + $storage, + count($storage->params) - 1, + ); - if (strpos($var_name, '$_') === 0 || (strpos($var_name, '$unused') === 0 && $var_name !== '$unused')) { - continue; - } + // Sort parameters in reverse order so that we can start from the end of parameters + krsort($unused_params, SORT_NUMERIC); - $position = array_search(substr($var_name, 1), array_keys($storage->param_lookup), true); + foreach ($unused_params as $unused_param_position => $unused_param_code_location) { + $unused_param_var_name = $storage->params[$unused_param_position]->name; + $unused_param_message = 'Param ' . $unused_param_var_name . ' is never referenced in this method'; - if ($position === false) { - throw new UnexpectedValueException('$position should not be false here'); - } + // Remove the key as we already report the issue + unset($unused_params[$unused_param_position]); - if ($storage->params[$position]->promoted_property) { - continue; - } - - $did_match_param = false; - - foreach ($this->function->params as $param) { - if ($param->var->getAttribute('endFilePos') === $original_location->raw_file_end) { - $did_match_param = true; + // Do not report unused required parameters + if ($unused_param_position !== $last_unused_argument_position) { break; } - } - if (!$did_match_param) { - continue; - } + $last_unused_argument_position = $this->detectPreviousUnusedArgumentPosition( + $storage, + $unused_param_position - 1, + ); - $assignment_node = DataFlowNode::getForAssignment($var_name, $original_location); - - if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph - && $statements_analyzer->data_flow_graph->isVariableUsed($assignment_node) - ) { - continue; - } - - if (!$storage instanceof MethodStorage - || !$storage->cased_name - || $storage->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE - ) { if ($this instanceof ClosureAnalyzer) { IssueBuffer::maybeAdd( new UnusedClosureParam( - 'Param ' . $var_name . ' is never referenced in this method', - $original_location, + $unused_param_message, + $unused_param_code_location, ), $this->getSuppressedIssues(), ); - } else { - IssueBuffer::maybeAdd( - new UnusedParam( - 'Param ' . $var_name . ' is never referenced in this method', - $original_location, - ), - $this->getSuppressedIssues(), - ); - } - } else { - $fq_class_name = (string)$context->self; - - $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); - - $method_name_lc = strtolower($storage->cased_name); - - if ($storage->abstract) { continue; } - if (isset($class_storage->overridden_method_ids[$method_name_lc])) { - $parent_method_id = end($class_storage->overridden_method_ids[$method_name_lc]); - - if ($parent_method_id) { - $parent_method_storage = $codebase->methods->getStorage($parent_method_id); - - // if the parent method has a param at that position and isn't abstract - if (!$parent_method_storage->abstract - && isset($parent_method_storage->params[$position]) - ) { - continue; - } - } - } - - $unused_params[$position] = $original_location; + IssueBuffer::maybeAdd( + new UnusedParam( + $unused_param_message, + $unused_param_code_location, + ), + $this->getSuppressedIssues(), + ); } } @@ -2076,4 +2041,120 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer $overridden_method_ids, ]; } + + /** + * @return array + */ + private function detectUnusedParameters( + StatementsAnalyzer $statements_analyzer, + FunctionLikeStorage $storage, + Context $context + ): array { + $codebase = $statements_analyzer->getCodebase(); + + $unused_params = []; + + foreach ($statements_analyzer->getUnusedVarLocations() as [$var_name, $original_location]) { + if (!array_key_exists(substr($var_name, 1), $storage->param_lookup)) { + continue; + } + + if ($this->isIgnoredForUnusedParam($var_name)) { + continue; + } + + $position = array_search(substr($var_name, 1), array_keys($storage->param_lookup), true); + + if ($position === false) { + throw new UnexpectedValueException('$position should not be false here'); + } + + if ($storage->params[$position]->promoted_property) { + continue; + } + + $did_match_param = false; + + foreach ($this->function->params as $param) { + if ($param->var->getAttribute('endFilePos') === $original_location->raw_file_end) { + $did_match_param = true; + break; + } + } + + if (!$did_match_param) { + continue; + } + + $assignment_node = DataFlowNode::getForAssignment($var_name, $original_location); + + if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph + && $statements_analyzer->data_flow_graph->isVariableUsed($assignment_node) + ) { + continue; + } + + if (!$storage instanceof MethodStorage + || !$storage->cased_name + || $storage->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE + ) { + $unused_params[$position] = $original_location; + continue; + } + + $fq_class_name = (string)$context->self; + + $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); + + $method_name_lc = strtolower($storage->cased_name); + + if ($storage->abstract) { + continue; + } + + if (isset($class_storage->overridden_method_ids[$method_name_lc])) { + $parent_method_id = end($class_storage->overridden_method_ids[$method_name_lc]); + + if ($parent_method_id) { + $parent_method_storage = $codebase->methods->getStorage($parent_method_id); + + // if the parent method has a param at that position and isn't abstract + if (!$parent_method_storage->abstract + && isset($parent_method_storage->params[$position]) + ) { + continue; + } + } + } + + $unused_params[$position] = $original_location; + } + + return $unused_params; + } + + private function detectPreviousUnusedArgumentPosition(FunctionLikeStorage $function, int $position): int + { + $params = $function->params; + krsort($params, SORT_NUMERIC); + + foreach ($params as $index => $param) { + if ($index > $position) { + continue; + } + + if ($this->isIgnoredForUnusedParam($param->name)) { + continue; + } + + return $index; + } + + return 0; + } + + private function isIgnoredForUnusedParam(string $var_name): bool + { + return strpos($var_name, '$_') === 0 || (strpos($var_name, '$unused') === 0 && $var_name !== '$unused'); + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php index 9187b76c..6b5d2809 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php @@ -15,6 +15,7 @@ use UnexpectedValueException; use function assert; use function count; use function implode; +use function is_string; use function preg_replace; use function strpos; use function strtolower; @@ -244,7 +245,7 @@ class NamespaceAnalyzer extends SourceAnalyzer while (($pos = strpos($identifier, "\\")) !== false) { if ($pos > 0) { $part = substr($identifier, 0, $pos); - assert($part !== ""); + assert(is_string($part) && $part !== ""); $parts[] = $part; } $parts[] = "\\"; @@ -253,13 +254,13 @@ class NamespaceAnalyzer extends SourceAnalyzer if (($pos = strpos($identifier, "::")) !== false) { if ($pos > 0) { $part = substr($identifier, 0, $pos); - assert($part !== ""); + assert(is_string($part) && $part !== ""); $parts[] = $part; } $parts[] = "::"; $identifier = substr($identifier, $pos + 2); } - if ($identifier !== "") { + if ($identifier !== "" && $identifier !== false) { $parts[] = $identifier; } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php index b874537f..6104e067 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php @@ -2,7 +2,6 @@ namespace Psalm\Internal\Analyzer; -use Amp\Loop; use Fidry\CpuCoreCounter\CpuCoreCounter; use Fidry\CpuCoreCounter\NumberOfCpuCoreNotFound; use InvalidArgumentException; @@ -15,8 +14,6 @@ use Psalm\FileManipulation; use Psalm\Internal\Codebase\TaintFlowGraph; use Psalm\Internal\FileManipulation\FileManipulationBuffer; use Psalm\Internal\LanguageServer\LanguageServer; -use Psalm\Internal\LanguageServer\ProtocolStreamReader; -use Psalm\Internal\LanguageServer\ProtocolStreamWriter; use Psalm\Internal\MethodIdentifier; use Psalm\Internal\Provider\ClassLikeStorageProvider; use Psalm\Internal\Provider\FileProvider; @@ -65,7 +62,6 @@ use function array_map; use function array_merge; use function array_shift; use function clearstatcache; -use function cli_set_process_title; use function count; use function defined; use function dirname; @@ -82,14 +78,9 @@ use function is_file; use function microtime; use function mkdir; use function number_format; -use function pcntl_fork; use function preg_match; use function rename; use function sprintf; -use function stream_set_blocking; -use function stream_socket_accept; -use function stream_socket_client; -use function stream_socket_server; use function strlen; use function strpos; use function strtolower; @@ -102,8 +93,6 @@ use const PHP_OS; use const PHP_VERSION; use const PSALM_VERSION; use const STDERR; -use const STDIN; -use const STDOUT; /** * @internal @@ -211,16 +200,6 @@ class ProjectAnalyzer UnnecessaryVarAnnotation::class, ]; - /** - * When this is true, the language server will send the diagnostic code with a help link. - */ - public bool $language_server_use_extended_diagnostic_codes = false; - - /** - * If this is true then the language server will send log messages to the client with additional information. - */ - public bool $language_server_verbose = false; - /** * @param array $generated_report_options */ @@ -230,12 +209,21 @@ class ProjectAnalyzer ?ReportOptions $stdout_report_options = null, array $generated_report_options = [], int $threads = 1, - ?Progress $progress = null + ?Progress $progress = null, + ?Codebase $codebase = null ) { if ($progress === null) { $progress = new VoidProgress(); } + if ($codebase === null) { + $codebase = new Codebase( + $config, + $providers, + $progress, + ); + } + $this->parser_cache_provider = $providers->parser_cache_provider; $this->project_cache_provider = $providers->project_cache_provider; $this->file_provider = $providers->file_provider; @@ -248,11 +236,7 @@ class ProjectAnalyzer $this->clearCacheDirectoryIfConfigOrComposerLockfileChanged(); - $this->codebase = new Codebase( - $config, - $providers, - $progress, - ); + $this->codebase = $codebase; $this->stdout_report_options = $stdout_report_options; $this->generated_report_options = $generated_report_options; @@ -394,10 +378,12 @@ class ProjectAnalyzer ); } - public function server(?string $address = '127.0.0.1:12345', bool $socket_server_mode = false): void + public function serverMode(LanguageServer $server): void { + $server->logInfo("Initializing: Visiting Autoload Files..."); $this->visitAutoloadFiles(); $this->codebase->diff_methods = true; + $server->logInfo("Initializing: Loading Reference Cache..."); $this->file_reference_provider->loadReferenceCache(); $this->codebase->enterServerMode(); @@ -418,103 +404,12 @@ class ProjectAnalyzer } } + $server->logInfo("Initializing: Initialize Plugins..."); $this->config->initializePlugins($this); foreach ($this->config->getProjectDirectories() as $dir_name) { $this->checkDirWithConfig($dir_name, $this->config); } - - @cli_set_process_title('Psalm ' . PSALM_VERSION . ' - PHP Language Server'); - - if (!$socket_server_mode && $address) { - // Connect to a TCP server - $socket = stream_socket_client('tcp://' . $address, $errno, $errstr); - if ($socket === false) { - fwrite(STDERR, "Could not connect to language client. Error $errno\n$errstr"); - exit(1); - } - stream_set_blocking($socket, false); - new LanguageServer( - new ProtocolStreamReader($socket), - new ProtocolStreamWriter($socket), - $this, - ); - Loop::run(); - } elseif ($socket_server_mode && $address) { - // Run a TCP Server - $tcpServer = stream_socket_server('tcp://' . $address, $errno, $errstr); - if ($tcpServer === false) { - fwrite(STDERR, "Could not listen on $address. Error $errno\n$errstr"); - exit(1); - } - fwrite(STDOUT, "Server listening on $address\n"); - - $fork_available = true; - if (!extension_loaded('pcntl')) { - fwrite(STDERR, "PCNTL is not available. Only a single connection will be accepted\n"); - $fork_available = false; - } - - $disabled_functions = array_map('trim', explode(',', ini_get('disable_functions'))); - if (in_array('pcntl_fork', $disabled_functions)) { - fwrite( - STDERR, - "pcntl_fork() is disabled by php configuration (disable_functions directive)." - . " Only a single connection will be accepted\n", - ); - $fork_available = false; - } - - while ($socket = stream_socket_accept($tcpServer, -1)) { - fwrite(STDOUT, "Connection accepted\n"); - stream_set_blocking($socket, false); - if ($fork_available) { - // If PCNTL is available, fork a child process for the connection - // An exit notification will only terminate the child process - $pid = pcntl_fork(); - if ($pid === -1) { - fwrite(STDERR, "Could not fork\n"); - exit(1); - } - - if ($pid === 0) { - // Child process - $reader = new ProtocolStreamReader($socket); - $reader->on( - 'close', - static function (): void { - fwrite(STDOUT, "Connection closed\n"); - }, - ); - new LanguageServer( - $reader, - new ProtocolStreamWriter($socket), - $this, - ); - // Just for safety - exit(0); - } - } else { - // If PCNTL is not available, we only accept one connection. - // An exit notification will terminate the server - new LanguageServer( - new ProtocolStreamReader($socket), - new ProtocolStreamWriter($socket), - $this, - ); - Loop::run(); - } - } - } else { - // Use STDIO - stream_set_blocking(STDIN, false); - new LanguageServer( - new ProtocolStreamReader(STDIN), - new ProtocolStreamWriter(STDOUT), - $this, - ); - Loop::run(); - } } /** @psalm-mutation-free */ @@ -1244,6 +1139,11 @@ class ProjectAnalyzer return $this->file_provider->fileExists($file_path); } + public function isDirectory(string $file_path): bool + { + return $this->file_provider->isDirectory($file_path); + } + public function alterCodeAfterCompletion( bool $dry_run = false, bool $safe_types = false diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php index 7baed128..bb55c91f 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php @@ -42,6 +42,7 @@ use Psalm\Type; use Psalm\Type\Atomic; use Psalm\Type\Atomic\Scalar; use Psalm\Type\Atomic\TArray; +use Psalm\Type\Atomic\TCallableObject; use Psalm\Type\Atomic\TFalse; use Psalm\Type\Atomic\TGenericObject; use Psalm\Type\Atomic\TIterable; @@ -190,7 +191,7 @@ class ForeachAnalyzer && $type_location && isset($context->vars_in_scope[$var_comment->var_id]) && $context->vars_in_scope[$var_comment->var_id]->getId() === $comment_type->getId() - && !$comment_type->isMixed() + && !$comment_type->isMixed(true) ) { $project_analyzer = $statements_analyzer->getProjectAnalyzer(); @@ -266,10 +267,6 @@ class ForeachAnalyzer $foreach_context = clone $context; - foreach ($foreach_context->vars_in_scope as $context_var_id => $context_type) { - $foreach_context->vars_in_scope[$context_var_id] = $context_type; - } - if ($var_id && $foreach_context->hasVariable($var_id)) { // refine the type of the array variable we iterate over // if we entered loop body, the array cannot be empty @@ -750,6 +747,7 @@ class ForeachAnalyzer foreach ($iterator_atomic_types as $iterator_atomic_type) { if ($iterator_atomic_type instanceof TTemplateParam || $iterator_atomic_type instanceof TObjectWithProperties + || $iterator_atomic_type instanceof TCallableObject ) { throw new UnexpectedValueException('Shouldn’t get a generic param here'); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseAnalyzer.php index 094b3fca..31fca6dc 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseAnalyzer.php @@ -169,7 +169,7 @@ class ElseAnalyzer $original_context, $new_assigned_var_ids, $new_possibly_assigned_var_ids, - [], + $if_scope->if_cond_changed_var_ids, true, ); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/LoopAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/LoopAnalyzer.php index cd6be47e..f1f5ad61 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/LoopAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/LoopAnalyzer.php @@ -108,11 +108,6 @@ class LoopAnalyzer if ($assignment_depth === 0 || $does_always_break) { $continue_context = clone $loop_context; - - foreach ($continue_context->vars_in_scope as $context_var_id => $context_type) { - $continue_context->vars_in_scope[$context_var_id] = $context_type; - } - $continue_context->loop_scope = $loop_scope; foreach ($pre_conditions as $condition_offset => $pre_condition) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayAnalyzer.php index 0c0e30fc..fa1fb7f1 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayAnalyzer.php @@ -333,19 +333,32 @@ class ArrayAnalyzer } elseif ($key_type->isSingleIntLiteral()) { $item_key_value = $key_type->getSingleIntLiteral()->value; - if ($item_key_value >= $array_creation_info->int_offset) { - if ($item_key_value === $array_creation_info->int_offset) { + if ($item_key_value <= PHP_INT_MAX + && $item_key_value > $array_creation_info->int_offset + ) { + if ($item_key_value - 1 === $array_creation_info->int_offset) { $item_is_list_item = true; } - $array_creation_info->int_offset = $item_key_value + 1; + $array_creation_info->int_offset = $item_key_value; } } } else { $key_type = Type::getArrayKey(); } } else { + if ($array_creation_info->int_offset === PHP_INT_MAX) { + IssueBuffer::maybeAdd( + new InvalidArrayOffset( + 'Cannot add an item with an offset beyond PHP_INT_MAX', + new CodeLocation($statements_analyzer->getSource(), $item), + ), + ); + return; + } + $item_is_list_item = true; - $item_key_value = $array_creation_info->int_offset++; + $item_key_value = ++$array_creation_info->int_offset; + $key_atomic_type = new TLiteralInt($item_key_value); $array_creation_info->item_key_atomic_types[] = $key_atomic_type; $key_type = new Union([$key_atomic_type]); @@ -538,7 +551,17 @@ class ArrayAnalyzer $array_creation_info->item_key_atomic_types[] = Type::getAtomicStringFromLiteral($new_offset); $array_creation_info->all_list = false; } else { - $new_offset = $array_creation_info->int_offset++; + if ($array_creation_info->int_offset === PHP_INT_MAX) { + IssueBuffer::maybeAdd( + new InvalidArrayOffset( + 'Cannot add an item with an offset beyond PHP_INT_MAX', + new CodeLocation($statements_analyzer->getSource(), $item->value), + ), + $statements_analyzer->getSuppressedIssues(), + ); + continue 2; + } + $new_offset = ++$array_creation_info->int_offset; $array_creation_info->item_key_atomic_types[] = new TLiteralInt($new_offset); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayCreationInfo.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayCreationInfo.php index f122b73f..43161d22 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayCreationInfo.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayCreationInfo.php @@ -38,7 +38,12 @@ class ArrayCreationInfo */ public array $array_keys = []; - public int $int_offset = 0; + /** + * Holds the integer offset of the *last* element added + * + * -1 may mean no elements have been added yet, but can also mean there's an element with offset -1 + */ + public int $int_offset = -1; public bool $all_list = true; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/InstancePropertyAssignmentAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/InstancePropertyAssignmentAnalyzer.php index 9435ea9e..127bab85 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/InstancePropertyAssignmentAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/InstancePropertyAssignmentAnalyzer.php @@ -1087,7 +1087,7 @@ class InstancePropertyAssignmentAnalyzer * If we have an explicit list of all allowed magic properties on the class, and we're * not in that list, fall through */ - if (!$var_id || !$class_storage->sealed_properties) { + if (!$var_id || !$class_storage->hasSealedProperties($codebase->config)) { if (!$context->collect_initializations && !$context->collect_mutations) { self::taintProperty( $statements_analyzer, diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php index 95b2adf3..509acb41 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php @@ -56,6 +56,7 @@ use Psalm\Issue\PossiblyUndefinedIntArrayOffset; use Psalm\Issue\ReferenceConstraintViolation; use Psalm\Issue\ReferenceReusedFromConfusingScope; use Psalm\Issue\UnnecessaryVarAnnotation; +use Psalm\Issue\UnsupportedPropertyReferenceUsage; use Psalm\IssueBuffer; use Psalm\Node\Expr\BinaryOp\VirtualBitwiseAnd; use Psalm\Node\Expr\BinaryOp\VirtualBitwiseOr; @@ -270,7 +271,7 @@ class AssignmentAnalyzer && $extended_var_id && (!$not_ignored_docblock_var_ids || isset($not_ignored_docblock_var_ids[$extended_var_id])) && $temp_assign_value_type->getId() === $comment_type->getId() - && !$comment_type->isMixed() + && !$comment_type->isMixed(true) ) { if ($codebase->alter_code && isset($statements_analyzer->getProjectAnalyzer()->getIssuesToFix()['UnnecessaryVarAnnotation']) @@ -980,10 +981,18 @@ class AssignmentAnalyzer $context->references_to_external_scope[$lhs_var_id] = true; } if (strpos($rhs_var_id, '->') !== false) { + IssueBuffer::maybeAdd(new UnsupportedPropertyReferenceUsage( + new CodeLocation($statements_analyzer->getSource(), $stmt), + )); // Reference to object property, we always consider object properties to be an external scope for references // TODO handle differently so it's detected as unused if the object is unused? $context->references_to_external_scope[$lhs_var_id] = true; } + if (strpos($rhs_var_id, '::') !== false) { + IssueBuffer::maybeAdd(new UnsupportedPropertyReferenceUsage( + new CodeLocation($statements_analyzer->getSource(), $stmt), + )); + } $lhs_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var); if (!$stmt->var instanceof ArrayDimFetch && !$stmt->var instanceof PropertyFetch) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php index d47b07ad..43da070b 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php @@ -71,7 +71,9 @@ use function reset; use function strpos; use function strtolower; use function substr; +use function substr_count; +use const DIRECTORY_SEPARATOR; use const PREG_SPLIT_NO_EMPTY; /** @@ -174,7 +176,9 @@ class ArgumentAnalyzer $prev_ord = $ord; } - if (count($values) < 12 || ($gt_count / count($values)) < 0.8) { + if (substr_count($arg_value_type->getSingleStringLiteral()->value, DIRECTORY_SEPARATOR) <= 2 + && (count($values) < 12 || ($gt_count / count($values)) < 0.8) + ) { IssueBuffer::maybeAdd( new InvalidLiteralArgument( 'Argument ' . ($argument_offset + 1) . ' of ' . $cased_method_id diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php index 33fbdbca..c9fdc523 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php @@ -20,7 +20,6 @@ use Psalm\Internal\Codebase\TaintFlowGraph; use Psalm\Internal\DataFlow\TaintSink; use Psalm\Internal\MethodIdentifier; use Psalm\Internal\Stubs\Generator\StubsGenerator; -use Psalm\Internal\Type\Comparator\CallableTypeComparator; use Psalm\Internal\Type\Comparator\UnionTypeComparator; use Psalm\Internal\Type\TemplateInferredTypeReplacer; use Psalm\Internal\Type\TemplateResult; @@ -197,18 +196,16 @@ class ArgumentsAnalyzer } $high_order_template_result = null; + $high_order_callable_info = $param + ? HighOrderFunctionArgHandler::getCallableArgInfo($context, $arg->value, $statements_analyzer, $param) + : null; - if (($arg->value instanceof PhpParser\Node\Expr\FuncCall - || $arg->value instanceof PhpParser\Node\Expr\MethodCall - || $arg->value instanceof PhpParser\Node\Expr\StaticCall) - && $param - && $function_storage = self::getHighOrderFuncStorage($context, $statements_analyzer, $arg->value) - ) { - $high_order_template_result = self::handleHighOrderFuncCallArg( + if ($param && $high_order_callable_info) { + $high_order_template_result = HighOrderFunctionArgHandler::remapLowerBounds( $statements_analyzer, $template_result ?? new TemplateResult([], []), - $function_storage, - $param, + $high_order_callable_info, + $param->type ?? Type::getMixed(), ); } elseif (($arg->value instanceof PhpParser\Node\Expr\Closure || $arg->value instanceof PhpParser\Node\Expr\ArrowFunction) @@ -228,7 +225,6 @@ class ArgumentsAnalyzer } $was_inside_call = $context->inside_call; - $context->inside_call = true; if (ExpressionAnalyzer::analyze( @@ -247,6 +243,16 @@ class ArgumentsAnalyzer $context->inside_call = $was_inside_call; + if ($high_order_callable_info && $high_order_template_result) { + HighOrderFunctionArgHandler::enhanceCallableArgType( + $context, + $arg->value, + $statements_analyzer, + $high_order_callable_info, + $high_order_template_result, + ); + } + if (($argument_offset === 0 && $method_id === 'array_filter' && count($args) === 2) || ($argument_offset > 0 && $method_id === 'array_map' && count($args) >= 2) ) { @@ -345,184 +351,6 @@ class ArgumentsAnalyzer } } - private static function getHighOrderFuncStorage( - Context $context, - StatementsAnalyzer $statements_analyzer, - PhpParser\Node\Expr\CallLike $function_like_call - ): ?FunctionLikeStorage { - $codebase = $statements_analyzer->getCodebase(); - - try { - if ($function_like_call instanceof PhpParser\Node\Expr\FuncCall && - !$function_like_call->isFirstClassCallable() - ) { - $function_id = strtolower((string) $function_like_call->name->getAttribute('resolvedName')); - - if (empty($function_id)) { - return null; - } - - if ($codebase->functions->dynamic_storage_provider->has($function_id)) { - return $codebase->functions->dynamic_storage_provider->getFunctionStorage( - $function_like_call, - $statements_analyzer, - $function_id, - $context, - new CodeLocation($statements_analyzer, $function_like_call), - ); - } - - return $codebase->functions->getStorage($statements_analyzer, $function_id); - } - - if ($function_like_call instanceof PhpParser\Node\Expr\MethodCall && - $function_like_call->var instanceof PhpParser\Node\Expr\Variable && - $function_like_call->name instanceof PhpParser\Node\Identifier && - is_string($function_like_call->var->name) && - isset($context->vars_in_scope['$' . $function_like_call->var->name]) - ) { - $lhs_type = $context->vars_in_scope['$' . $function_like_call->var->name]->getSingleAtomic(); - - if (!$lhs_type instanceof Type\Atomic\TNamedObject) { - return null; - } - - $method_id = new MethodIdentifier( - $lhs_type->value, - strtolower((string)$function_like_call->name), - ); - - return $codebase->methods->getStorage($method_id); - } - - if ($function_like_call instanceof PhpParser\Node\Expr\StaticCall && - $function_like_call->name instanceof PhpParser\Node\Identifier - ) { - $method_id = new MethodIdentifier( - (string)$function_like_call->class->getAttribute('resolvedName'), - strtolower($function_like_call->name->name), - ); - - return $codebase->methods->getStorage($method_id); - } - } catch (UnexpectedValueException $e) { - return null; - } - - return null; - } - - /** - * Compiles TemplateResult for high-order functions ($func_call) - * by previous template args ($inferred_template_result). - * - * It's need for proper template replacement: - * - * ``` - * * template T - * * return Closure(T): T - * function id(): Closure { ... } - * - * * template A - * * template B - * * - * * param list $_items - * * param callable(A): B $_ab - * * return list - * function map(array $items, callable $ab): array { ... } - * - * // list - * $numbers = [1, 2, 3]; - * - * $result = map($numbers, id()); - * // $result is list because template T of id() was inferred by previous arg. - * ``` - */ - private static function handleHighOrderFuncCallArg( - StatementsAnalyzer $statements_analyzer, - TemplateResult $inferred_template_result, - FunctionLikeStorage $storage, - FunctionLikeParameter $actual_func_param - ): ?TemplateResult { - $codebase = $statements_analyzer->getCodebase(); - - $input_hof_atomic = $storage->return_type && $storage->return_type->isSingle() - ? $storage->return_type->getSingleAtomic() - : null; - - // Try upcast invokable to callable type. - if ($input_hof_atomic instanceof Type\Atomic\TNamedObject && - $input_hof_atomic->value !== 'Closure' && - $codebase->classExists($input_hof_atomic->value) - ) { - $callable_from_invokable = CallableTypeComparator::getCallableFromAtomic( - $codebase, - $input_hof_atomic, - ); - - if ($callable_from_invokable) { - $invoke_id = new MethodIdentifier($input_hof_atomic->value, '__invoke'); - $declaring_invoke_id = $codebase->methods->getDeclaringMethodId($invoke_id); - - $storage = $codebase->methods->getStorage($declaring_invoke_id ?? $invoke_id); - $input_hof_atomic = $callable_from_invokable; - } - } - - if (!$input_hof_atomic instanceof TClosure && !$input_hof_atomic instanceof TCallable) { - return null; - } - - $container_hof_atomic = $actual_func_param->type && $actual_func_param->type->isSingle() - ? $actual_func_param->type->getSingleAtomic() - : null; - - if (!$container_hof_atomic instanceof TClosure && !$container_hof_atomic instanceof TCallable) { - return null; - } - - $replaced_container_hof_atomic = new Union([$container_hof_atomic]); - - // Replaces all input args in container function. - // - // For example: - // The map function expects callable(A):B as second param - // We know that previous arg type is list where the int is the A template. - // Then we can replace callable(A): B to callable(int):B using $inferred_template_result. - $replaced_container_hof_atomic = TemplateInferredTypeReplacer::replace( - $replaced_container_hof_atomic, - $inferred_template_result, - $codebase, - ); - - /** @var TClosure|TCallable $container_hof_atomic */ - $container_hof_atomic = $replaced_container_hof_atomic->getSingleAtomic(); - $high_order_template_result = new TemplateResult($storage->template_types ?: [], []); - - // We can replace each templated param for the input function. - // Example: - // map($numbers, id()); - // We know that map expects callable(int):B because the $numbers is list. - // We know that id() returns callable(T):T. - // Then we can replace templated params sequentially using the expected callable(int):B. - foreach ($input_hof_atomic->params ?? [] as $offset => $actual_func_param) { - if ($actual_func_param->type && - $actual_func_param->type->getTemplateTypes() && - isset($container_hof_atomic->params[$offset]) - ) { - TemplateStandinTypeReplacer::fillTemplateResult( - $actual_func_param->type, - $high_order_template_result, - $codebase, - null, - $container_hof_atomic->params[$offset]->type, - ); - } - } - - return $high_order_template_result; - } - /** * @param array $args */ @@ -930,7 +758,7 @@ class ArgumentsAnalyzer IssueBuffer::maybeAdd( new InvalidNamedArgument( 'Parameter $' . $key_type->value . ' does not exist on function ' - . ($cased_method_id ?: $method_id), + . ($cased_method_id ?: $method_id), new CodeLocation($statements_analyzer, $arg), (string)$method_id, ), @@ -970,7 +798,7 @@ class ArgumentsAnalyzer IssueBuffer::maybeAdd( new InvalidNamedArgument( 'Parameter $' . $arg->name->name . ' does not exist on function ' - . ($cased_method_id ?: $method_id), + . ($cased_method_id ?: $method_id), new CodeLocation($statements_analyzer, $arg->name), (string) $method_id, ), diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArrayFunctionArgumentsAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArrayFunctionArgumentsAnalyzer.php index 8b55808b..c1aa8540 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArrayFunctionArgumentsAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArrayFunctionArgumentsAnalyzer.php @@ -14,6 +14,7 @@ use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer; use Psalm\Internal\Analyzer\StatementsAnalyzer; use Psalm\Internal\Codebase\InternalCallMapHandler; use Psalm\Internal\MethodIdentifier; +use Psalm\Internal\Type\ArrayType; use Psalm\Internal\Type\Comparator\TypeComparisonResult; use Psalm\Internal\Type\Comparator\UnionTypeComparator; use Psalm\Internal\Type\TemplateResult; @@ -41,12 +42,14 @@ use Psalm\Type\Union; use UnexpectedValueException; use function array_filter; +use function array_merge; use function array_pop; use function array_shift; use function array_unshift; use function assert; use function count; use function explode; +use function is_numeric; use function strpos; use function strtolower; use function substr; @@ -346,6 +349,40 @@ class ArrayFunctionArgumentsAnalyzer return false; } + $array_type = null; + $array_size = null; + + if (($array_arg_type = $statements_analyzer->node_data->getType($array_arg)) + && $array_arg_type->hasArray() + ) { + /** + * @var TArray|TKeyedArray + */ + $array_type = $array_arg_type->getArray(); + if ($generic_array_type = ArrayType::infer($array_type)) { + $array_size = $generic_array_type->count; + } + + if ($array_type instanceof TKeyedArray) { + if ($array_type->is_list && isset($args[3])) { + $array_type = Type::getNonEmptyListAtomic($array_type->getGenericValueType()); + } else { + $array_type = $array_type->getGenericArrayType(); + } + } + + if ($array_type instanceof TArray + && $array_type->type_params[0]->hasInt() + && !$array_type->type_params[0]->hasString() + ) { + if ($array_type instanceof TNonEmptyArray && isset($args[3])) { + $array_type = Type::getNonEmptyListAtomic($array_type->type_params[1]); + } else { + $array_type = Type::getListAtomic($array_type->type_params[1]); + } + } + } + $offset_arg = $args[1]->value; if (ExpressionAnalyzer::analyze( @@ -356,7 +393,47 @@ class ArrayFunctionArgumentsAnalyzer return false; } + $offset_arg_is_zero = false; + + if (($offset_arg_type = $statements_analyzer->node_data->getType($offset_arg)) + && $offset_arg_type->hasLiteralValue() && $offset_arg_type->isSingleLiteral() + ) { + $offset_literal_value = $offset_arg_type->getSingleLiteral()->value; + $offset_arg_is_zero = is_numeric($offset_literal_value) && ((int) $offset_literal_value)===0; + } + if (!isset($args[2])) { + if ($offset_arg_is_zero) { + $array_type = Type::getEmptyArray(); + AssignmentAnalyzer::assignByRefParam( + $statements_analyzer, + $array_arg, + $array_type, + $array_type, + $context, + false, + ); + } elseif ($array_type) { + AssignmentAnalyzer::assignByRefParam( + $statements_analyzer, + $array_arg, + new Union([$array_type]), + new Union([$array_type]), + $context, + false, + ); + } else { + $default_array_type = Type::getArray(); + AssignmentAnalyzer::assignByRefParam( + $statements_analyzer, + $array_arg, + $default_array_type, + $default_array_type, + $context, + false, + ); + } + return null; } @@ -370,7 +447,69 @@ class ArrayFunctionArgumentsAnalyzer return false; } + $cover_whole_arr = false; + if ($offset_arg_is_zero && is_numeric($array_size)) { + if (($length_arg_type = $statements_analyzer->node_data->getType($length_arg)) + && $length_arg_type->hasLiteralValue() + ) { + $length_min = null; + if ($length_arg_type->isSingleLiteral()) { + $length_literal = $length_arg_type->getSingleLiteral(); + if ($length_literal->isNumericType()) { + $length_min = (int) $length_literal->value; + } + } else { + $literals = array_merge( + $length_arg_type->getLiteralStrings(), + $length_arg_type->getLiteralInts(), + $length_arg_type->getLiteralFloats(), + ); + foreach ($literals as $literal) { + if ($literal->isNumericType() + && ($literal_val = (int) $literal->value) + && ((isset($length_min) && $length_min> $literal_val) || !isset($length_min))) { + $length_min = $literal_val; + } + } + } + $cover_whole_arr = isset($length_min) && $length_min>= $array_size; + } elseif ($length_arg_type&& $length_arg_type->isNull()) { + $cover_whole_arr = true; + } + } + if (!isset($args[3])) { + if ($cover_whole_arr) { + $array_type = Type::getEmptyArray(); + AssignmentAnalyzer::assignByRefParam( + $statements_analyzer, + $array_arg, + $array_type, + $array_type, + $context, + false, + ); + } elseif ($array_type) { + AssignmentAnalyzer::assignByRefParam( + $statements_analyzer, + $array_arg, + new Union([$array_type]), + new Union([$array_type]), + $context, + false, + ); + } else { + $default_array_type = Type::getArray(); + AssignmentAnalyzer::assignByRefParam( + $statements_analyzer, + $array_arg, + $default_array_type, + $default_array_type, + $context, + false, + ); + } + return null; } @@ -400,40 +539,31 @@ class ArrayFunctionArgumentsAnalyzer $statements_analyzer->node_data->setType($replacement_arg, $replacement_arg_type); } - if (($array_arg_type = $statements_analyzer->node_data->getType($array_arg)) - && $array_arg_type->hasArray() + if ($array_type && $replacement_arg_type && $replacement_arg_type->hasArray() ) { - /** - * @var TArray|TKeyedArray - */ - $array_type = $array_arg_type->getArray(); - - if ($array_type instanceof TKeyedArray) { - if ($array_type->is_list) { - $array_type = Type::getNonEmptyListAtomic($array_type->getGenericValueType()); - } else { - $array_type = $array_type->getGenericArrayType(); - } - } - - if ($array_type instanceof TArray - && $array_type->type_params[0]->hasInt() - && !$array_type->type_params[0]->hasString() - ) { - if ($array_type instanceof TNonEmptyArray) { - $array_type = Type::getNonEmptyListAtomic($array_type->type_params[1]); - } else { - $array_type = Type::getListAtomic($array_type->type_params[1]); - } - } - /** * @var TArray|TKeyedArray */ $replacement_array_type = $replacement_arg_type->getArray(); + if (($replacement_array_type_generic = ArrayType::infer($replacement_array_type)) + && $replacement_array_type_generic->count === 0 + && $cover_whole_arr) { + $empty_array_type = Type::getEmptyArray(); + AssignmentAnalyzer::assignByRefParam( + $statements_analyzer, + $array_arg, + $empty_array_type, + $empty_array_type, + $context, + false, + ); + + return null; + } + if ($replacement_array_type instanceof TKeyedArray) { $was_list = $replacement_array_type->is_list; @@ -462,16 +592,26 @@ class ArrayFunctionArgumentsAnalyzer return null; } - $array_type = Type::getArray(); - - AssignmentAnalyzer::assignByRefParam( - $statements_analyzer, - $array_arg, - $array_type, - $array_type, - $context, - false, - ); + if ($array_type) { + AssignmentAnalyzer::assignByRefParam( + $statements_analyzer, + $array_arg, + new Union([$array_type]), + new Union([$array_type]), + $context, + false, + ); + } else { + $default_array_type = Type::getArray(); + AssignmentAnalyzer::assignByRefParam( + $statements_analyzer, + $array_arg, + $default_array_type, + $default_array_type, + $context, + false, + ); + } return null; } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php index 0ad6a6a8..7ecfff03 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php @@ -723,8 +723,17 @@ class FunctionCallAnalyzer extends CallAnalyzer ), $statements_analyzer->getSuppressedIssues(), ); - } elseif ($var_type_part instanceof TCallableObject - || $var_type_part instanceof TCallableString + } elseif ($var_type_part instanceof TCallableObject) { + $has_valid_function_call_type = true; + self::analyzeInvokeCall( + $statements_analyzer, + $stmt, + $real_stmt, + $function_name, + $context, + $var_type_part, + ); + } elseif ($var_type_part instanceof TCallableString || ($var_type_part instanceof TNamedObject && $var_type_part->value === 'Closure') || ($var_type_part instanceof TObjectWithProperties && isset($var_type_part->methods['__invoke'])) ) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php index 123437eb..7941941c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php @@ -482,15 +482,25 @@ class FunctionCallReturnTypeFetcher return $call_map_return_type; case 'mb_strtolower': + $string_arg_type = $statements_analyzer->node_data->getType($call_args[0]->value); + if ($string_arg_type !== null && $string_arg_type->isNonEmptyString()) { + $returnType = Type::getNonEmptyLowercaseString(); + } else { + $returnType = Type::getLowercaseString(); + } if (count($call_args) < 2) { - return Type::getLowercaseString(); + return $returnType; } else { $second_arg_type = $statements_analyzer->node_data->getType($call_args[1]->value); if ($second_arg_type && $second_arg_type->isNull()) { - return Type::getLowercaseString(); + return $returnType; } } - return Type::getString(); + if ($string_arg_type !== null && $string_arg_type->isNonEmptyString()) { + return Type::getNonEmptyString(); + } else { + return Type::getString(); + } } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgHandler.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgHandler.php new file mode 100644 index 00000000..3d1a51c4 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgHandler.php @@ -0,0 +1,325 @@ + $_items + * * param callable(A): B $_ab + * * return list + * function map(array $items, callable $ab): array { ... } + * + * // list + * $numbers = [1, 2, 3]; + * + * $result = map($numbers, id()); + * // $result is list because template T of id() was inferred by previous arg. + * ``` + */ + public static function remapLowerBounds( + StatementsAnalyzer $statements_analyzer, + TemplateResult $inferred_template_result, + HighOrderFunctionArgInfo $input_function, + Union $container_function_type + ): TemplateResult { + // Try to infer container callable by $inferred_template_result + $container_type = TemplateInferredTypeReplacer::replace( + $container_function_type, + $inferred_template_result, + $statements_analyzer->getCodebase(), + ); + + $input_function_type = $input_function->getFunctionType(); + $input_function_template_result = $input_function->getTemplates(); + + // Traverse side by side 'container' params and 'input' params. + // This maps 'input' templates to 'container' templates. + // + // Example: + // 'input' => Closure(C:Bar, D:Bar): array{C:Bar, D:Bar} + // 'container' => Closure(int, string): array{int, string} + // + // $remapped_lower_bounds will be: [ + // 'C' => ['Bar' => [int]], + // 'D' => ['Bar' => [string]] + // ]. + foreach ($input_function_type->getAtomicTypes() as $input_atomic) { + if (!$input_atomic instanceof TClosure && !$input_atomic instanceof TCallable) { + continue; + } + + foreach ($container_type->getAtomicTypes() as $container_atomic) { + if (!$container_atomic instanceof TClosure && !$container_atomic instanceof TCallable) { + continue; + } + + foreach ($input_atomic->params ?? [] as $offset => $input_param) { + if (!isset($container_atomic->params[$offset])) { + continue; + } + + TemplateStandinTypeReplacer::fillTemplateResult( + $input_param->type ?? Type::getMixed(), + $input_function_template_result, + $statements_analyzer->getCodebase(), + $statements_analyzer, + $container_atomic->params[$offset]->type, + ); + } + } + } + + return $input_function_template_result; + } + + public static function enhanceCallableArgType( + Context $context, + PhpParser\Node\Expr $arg_expr, + StatementsAnalyzer $statements_analyzer, + HighOrderFunctionArgInfo $high_order_callable_info, + TemplateResult $high_order_template_result + ): void { + // Psalm can infer simple callable/closure. + // But can't infer first-class-callable or high-order function. + if ($high_order_callable_info->getType() === HighOrderFunctionArgInfo::TYPE_CALLABLE) { + return; + } + + $fully_inferred_callable_type = TemplateInferredTypeReplacer::replace( + $high_order_callable_info->getFunctionType(), + $high_order_template_result, + $statements_analyzer->getCodebase(), + ); + + // Some templates may not have been replaced. + // They expansion makes error message better. + $expanded = TypeExpander::expandUnion( + $statements_analyzer->getCodebase(), + $fully_inferred_callable_type, + $context->self, + $context->self, + $context->parent, + true, + true, + false, + false, + true, + ); + + $statements_analyzer->node_data->setType($arg_expr, $expanded); + } + + public static function getCallableArgInfo( + Context $context, + PhpParser\Node\Expr $input_arg_expr, + StatementsAnalyzer $statements_analyzer, + FunctionLikeParameter $container_param + ): ?HighOrderFunctionArgInfo { + if (!self::isSupported($container_param)) { + return null; + } + + $codebase = $statements_analyzer->getCodebase(); + + try { + if ($input_arg_expr instanceof PhpParser\Node\Expr\FuncCall) { + $function_id = strtolower((string) $input_arg_expr->name->getAttribute('resolvedName')); + + if (empty($function_id)) { + return null; + } + + $dynamic_storage = !$input_arg_expr->isFirstClassCallable() + ? $codebase->functions->dynamic_storage_provider->getFunctionStorage( + $input_arg_expr, + $statements_analyzer, + $function_id, + $context, + new CodeLocation($statements_analyzer, $input_arg_expr), + ) + : null; + + return new HighOrderFunctionArgInfo( + $input_arg_expr->isFirstClassCallable() + ? HighOrderFunctionArgInfo::TYPE_FIRST_CLASS_CALLABLE + : HighOrderFunctionArgInfo::TYPE_CALLABLE, + $dynamic_storage ?? $codebase->functions->getStorage($statements_analyzer, $function_id), + ); + } + + if ($input_arg_expr instanceof PhpParser\Node\Expr\MethodCall && + $input_arg_expr->var instanceof PhpParser\Node\Expr\Variable && + $input_arg_expr->name instanceof PhpParser\Node\Identifier && + is_string($input_arg_expr->var->name) && + isset($context->vars_in_scope['$' . $input_arg_expr->var->name]) + ) { + $lhs_type = $context->vars_in_scope['$' . $input_arg_expr->var->name]->getSingleAtomic(); + + if (!$lhs_type instanceof Type\Atomic\TNamedObject) { + return null; + } + + $method_id = new MethodIdentifier( + $lhs_type->value, + strtolower((string)$input_arg_expr->name), + ); + + return new HighOrderFunctionArgInfo( + $input_arg_expr->isFirstClassCallable() + ? HighOrderFunctionArgInfo::TYPE_FIRST_CLASS_CALLABLE + : HighOrderFunctionArgInfo::TYPE_CALLABLE, + $codebase->methods->getStorage($method_id), + ); + } + + if ($input_arg_expr instanceof PhpParser\Node\Expr\StaticCall && + $input_arg_expr->name instanceof PhpParser\Node\Identifier + ) { + $method_id = new MethodIdentifier( + (string)$input_arg_expr->class->getAttribute('resolvedName'), + strtolower($input_arg_expr->name->toString()), + ); + + return new HighOrderFunctionArgInfo( + $input_arg_expr->isFirstClassCallable() + ? HighOrderFunctionArgInfo::TYPE_FIRST_CLASS_CALLABLE + : HighOrderFunctionArgInfo::TYPE_CALLABLE, + $codebase->methods->getStorage($method_id), + ); + } + + if ($input_arg_expr instanceof PhpParser\Node\Scalar\String_) { + return self::fromLiteralString(Type::getString($input_arg_expr->value), $statements_analyzer); + } + + if ($input_arg_expr instanceof PhpParser\Node\Expr\ConstFetch) { + $constant = $context->constants[$input_arg_expr->name->toString()] ?? null; + + return null !== $constant + ? self::fromLiteralString($constant, $statements_analyzer) + : null; + } + + if ($input_arg_expr instanceof PhpParser\Node\Expr\ClassConstFetch && + $input_arg_expr->name instanceof PhpParser\Node\Identifier + ) { + $storage = $codebase->classlikes + ->getStorageFor((string)$input_arg_expr->class->getAttribute('resolvedName')); + + $constant = null !== $storage + ? $storage->constants[$input_arg_expr->name->toString()] ?? null + : null; + + return null !== $constant && null !== $constant->type + ? self::fromLiteralString($constant->type, $statements_analyzer) + : null; + } + + if ($input_arg_expr instanceof PhpParser\Node\Expr\New_ && + $input_arg_expr->class instanceof PhpParser\Node\Name + ) { + $class_storage = $codebase->classlikes + ->getStorageFor((string) $input_arg_expr->class->getAttribute('resolvedName')); + + $invoke_storage = $class_storage && isset($class_storage->methods['__invoke']) + ? $class_storage->methods['__invoke'] + : null; + + if (!$invoke_storage) { + return null; + } + + return new HighOrderFunctionArgInfo( + HighOrderFunctionArgInfo::TYPE_CLASS_CALLABLE, + $invoke_storage, + $class_storage, + ); + } + } catch (UnexpectedValueException $e) { + return null; + } + + return null; + } + + private static function isSupported(FunctionLikeParameter $container_param): bool + { + if (!$container_param->type || !$container_param->type->hasCallableType()) { + return false; + } + + foreach ($container_param->type->getAtomicTypes() as $a) { + if (($a instanceof TClosure || $a instanceof TCallable) && !$a->params) { + return false; + } + + if ($a instanceof Type\Atomic\TCallableArray || + $a instanceof Type\Atomic\TCallableString || + $a instanceof Type\Atomic\TCallableKeyedArray + ) { + return false; + } + } + + return true; + } + + private static function fromLiteralString( + Union $constant, + StatementsAnalyzer $statements_analyzer + ): ?HighOrderFunctionArgInfo { + $literal = $constant->isSingle() ? $constant->getSingleAtomic() : null; + + if (!$literal instanceof Type\Atomic\TLiteralString || empty($literal->value)) { + return null; + } + + $codebase = $statements_analyzer->getCodebase(); + + return new HighOrderFunctionArgInfo( + HighOrderFunctionArgInfo::TYPE_STRING_CALLABLE, + strpos($literal->value, '::') !== false + ? $codebase->methods->getStorage(MethodIdentifier::wrap($literal->value)) + : $codebase->functions->getStorage($statements_analyzer, strtolower($literal->value)), + ); + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgInfo.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgInfo.php new file mode 100644 index 00000000..526e6ee1 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgInfo.php @@ -0,0 +1,90 @@ +type = $type; + $this->function_storage = $function_storage; + $this->class_storage = $class_storage; + } + + public function getTemplates(): TemplateResult + { + $templates = $this->class_storage + ? array_merge( + $this->function_storage->template_types ?? [], + $this->class_storage->template_types ?? [], + ) + : $this->function_storage->template_types ?? []; + + return new TemplateResult($templates, []); + } + + public function getType(): string + { + return $this->type; + } + + public function getFunctionType(): Union + { + switch ($this->type) { + case self::TYPE_FIRST_CLASS_CALLABLE: + return new Union([ + new TClosure( + 'Closure', + $this->function_storage->params, + $this->function_storage->return_type, + $this->function_storage->pure, + ), + ]); + + case self::TYPE_STRING_CALLABLE: + case self::TYPE_CLASS_CALLABLE: + return new Union([ + new TCallable( + 'callable', + $this->function_storage->params, + $this->function_storage->return_type, + $this->function_storage->pure, + ), + ]); + + default: + return $this->function_storage->return_type ?? Type::getMixed(); + } + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalyzer.php index 74109d03..4e6d3188 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalyzer.php @@ -27,6 +27,8 @@ use Psalm\StatementsSource; use Psalm\Storage\ClassLikeStorage; use Psalm\Type; use Psalm\Type\Atomic; +use Psalm\Type\Atomic\TCallable; +use Psalm\Type\Atomic\TCallableObject; use Psalm\Type\Atomic\TClosure; use Psalm\Type\Atomic\TEmptyMixed; use Psalm\Type\Atomic\TFalse; @@ -104,6 +106,18 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer $source = $statements_analyzer->getSource(); + if ($lhs_type_part instanceof TCallableObject) { + self::handleCallableObject( + $statements_analyzer, + $stmt, + $context, + $lhs_type_part->callable, + $result, + $inferred_template_result, + ); + return; + } + if (!$lhs_type_part instanceof TNamedObject) { self::handleInvalidClass( $statements_analyzer, @@ -891,4 +905,55 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer $fq_class_name, ]; } + + private static function handleCallableObject( + StatementsAnalyzer $statements_analyzer, + PhpParser\Node\Expr\MethodCall $stmt, + Context $context, + ?TCallable $lhs_type_part_callable, + AtomicMethodCallAnalysisResult $result, + ?TemplateResult $inferred_template_result = null + ): void { + $method_id = 'object::__invoke'; + $result->existent_method_ids[] = $method_id; + $result->has_valid_method_call_type = true; + + if ($lhs_type_part_callable !== null) { + $result->return_type = $lhs_type_part_callable->return_type ?? Type::getMixed(); + $callableArgumentCount = count($lhs_type_part_callable->params ?? []); + $providedArgumentsCount = count($stmt->getArgs()); + + if ($callableArgumentCount > $providedArgumentsCount) { + $result->too_few_arguments = true; + $result->too_few_arguments_method_ids[] = new MethodIdentifier('callable-object', '__invoke'); + } elseif ($providedArgumentsCount > $callableArgumentCount) { + $result->too_many_arguments = true; + $result->too_many_arguments_method_ids[] = new MethodIdentifier('callable-object', '__invoke'); + } + + $template_result = $inferred_template_result ?? new TemplateResult([], []); + + ArgumentsAnalyzer::analyze( + $statements_analyzer, + $stmt->getArgs(), + $lhs_type_part_callable->params, + $method_id, + false, + $context, + $template_result, + ); + + ArgumentsAnalyzer::checkArgumentsMatch( + $statements_analyzer, + $stmt->getArgs(), + $method_id, + $lhs_type_part_callable->params ?? [], + null, + null, + $template_result, + new CodeLocation($statements_analyzer->getSource(), $stmt), + $context, + ); + } + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php index c3f4717e..980043f1 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php @@ -42,10 +42,13 @@ use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Union; use UnexpectedValueException; +use function array_filter; use function array_map; use function count; use function explode; use function in_array; +use function is_string; +use function strpos; use function strtolower; /** @@ -225,6 +228,9 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer if ($inferred_template_result) { $template_result->lower_bounds += $inferred_template_result->lower_bounds; } + if ($method_storage && $method_storage->template_types) { + $template_result->template_types += $method_storage->template_types; + } if ($codebase->store_node_types && !$stmt->isFirstClassCallable() @@ -422,30 +428,48 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer } if ($method_storage->if_true_assertions) { + $possibilities = array_map( + static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy( + $template_result, + $lhs_var_id, + $codebase, + ), + $method_storage->if_true_assertions, + ); + if ($lhs_var_id === null) { + $possibilities = array_filter( + $possibilities, + static fn(Possibilities $assertion): bool => !(is_string($assertion->var_id) + && strpos($assertion->var_id, '$this->') === 0 + ) + ); + } $statements_analyzer->node_data->setIfTrueAssertions( $stmt, - array_map( - static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy( - $template_result, - $lhs_var_id, - $codebase, - ), - $method_storage->if_true_assertions, - ), + $possibilities, ); } if ($method_storage->if_false_assertions) { + $possibilities = array_map( + static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy( + $template_result, + $lhs_var_id, + $codebase, + ), + $method_storage->if_false_assertions, + ); + if ($lhs_var_id === null) { + $possibilities = array_filter( + $possibilities, + static fn(Possibilities $assertion): bool => !(is_string($assertion->var_id) + && strpos($assertion->var_id, '$this->') === 0 + ) + ); + } $statements_analyzer->node_data->setIfFalseAssertions( $stmt, - array_map( - static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy( - $template_result, - $lhs_var_id, - $codebase, - ), - $method_storage->if_false_assertions, - ), + $possibilities, ); } } @@ -546,7 +570,7 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer case '__set': // If `@psalm-seal-properties` is set, the property must be defined with // a `@property` annotation - if (($class_storage->sealed_properties || $codebase->config->seal_all_properties) + if (($class_storage->hasSealedProperties($codebase->config)) && !isset($class_storage->pseudo_property_set_types['$' . $prop_name]) ) { IssueBuffer::maybeAdd( @@ -644,7 +668,7 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer case '__get': // If `@psalm-seal-properties` is set, the property must be defined with // a `@property` annotation - if (($class_storage->sealed_properties || $codebase->config->seal_all_properties) + if (($class_storage->hasSealedProperties($codebase->config)) && !isset($class_storage->pseudo_property_get_types['$' . $prop_name]) ) { IssueBuffer::maybeAdd( diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MissingMethodCallHandler.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MissingMethodCallHandler.php index 2f16c392..8e9346d8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MissingMethodCallHandler.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MissingMethodCallHandler.php @@ -190,7 +190,7 @@ class MissingMethodCallHandler $context, ); - if ($class_storage->sealed_methods || $config->seal_all_methods) { + if ($class_storage->hasSealedMethods($config)) { $result->non_existent_magic_method_ids[] = $method_id->__toString(); return null; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php index 0087a585..b521f8bc 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php @@ -52,12 +52,11 @@ use Psalm\Type\Atomic\TObject; use Psalm\Type\Atomic\TString; use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Atomic\TTemplateParamClass; +use Psalm\Type\Atomic\TUnknownClassString; use Psalm\Type\TaintKind; use Psalm\Type\Union; use function array_map; -use function array_merge; -use function array_shift; use function array_values; use function implode; use function in_array; @@ -74,7 +73,8 @@ class NewAnalyzer extends CallAnalyzer public static function analyze( StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\New_ $stmt, - Context $context + Context $context, + TemplateResult $template_result = null ): bool { $fq_class_name = null; @@ -256,6 +256,7 @@ class NewAnalyzer extends CallAnalyzer $fq_class_name, $from_static, $can_extend, + $template_result, ); } else { ArgumentsAnalyzer::analyze( @@ -291,7 +292,8 @@ class NewAnalyzer extends CallAnalyzer Context $context, string $fq_class_name, bool $from_static, - bool $can_extend + bool $can_extend, + TemplateResult $template_result = null ): void { $storage = $codebase->classlike_storage_provider->get($fq_class_name); @@ -392,7 +394,7 @@ class NewAnalyzer extends CallAnalyzer ); } - $template_result = new TemplateResult([], []); + $template_result ??= new TemplateResult([], []); if (self::checkMethodArgs( $method_id, @@ -699,15 +701,58 @@ class NewAnalyzer extends CallAnalyzer } } - $new_type = null; + $new_type = self::getNewType( + $statements_analyzer, + $codebase, + $context, + $stmt, + $stmt_class_type, + $config, + $can_extend, + ); - $stmt_class_types = $stmt_class_type->getAtomicTypes(); + if (!$has_single_class) { + if ($new_type) { + $statements_analyzer->node_data->setType($stmt, $new_type); + } - while ($stmt_class_types) { - $lhs_type_part = array_shift($stmt_class_types); + ArgumentsAnalyzer::analyze( + $statements_analyzer, + $stmt->getArgs(), + null, + null, + true, + $context, + ); + return; + } + } + private static function getNewType( + StatementsAnalyzer $statements_analyzer, + Codebase $codebase, + Context $context, + PhpParser\Node\Expr\New_ $stmt, + Union $stmt_class_type, + Config $config, + bool &$can_extend + ): ?Union { + $new_types = []; + + foreach ($stmt_class_type->getAtomicTypes() as $lhs_type_part) { if ($lhs_type_part instanceof TTemplateParam) { - $stmt_class_types = array_merge($stmt_class_types, $lhs_type_part->as->getAtomicTypes()); + $as = self::getNewType( + $statements_analyzer, + $codebase, + $context, + $stmt, + $lhs_type_part->as, + $config, + $can_extend, + ); + if ($as) { + $new_types []= new Union([$lhs_type_part->replaceAs($as)]); + } continue; } @@ -731,7 +776,7 @@ class NewAnalyzer extends CallAnalyzer ); } - $new_type = Type::combineUnionTypes($new_type, new Union([$new_type_part])); + $new_types []= new Union([$new_type_part]); if ($lhs_type_part->as_type && $codebase->classlikes->classExists($lhs_type_part->as_type->value) @@ -777,9 +822,10 @@ class NewAnalyzer extends CallAnalyzer ) { if (!$statements_analyzer->node_data->getType($stmt)) { if ($lhs_type_part instanceof TClassString) { - $generated_type = $lhs_type_part->as_type - ? $lhs_type_part->as_type - : new TObject(); + $generated_type = $lhs_type_part->as_type ?? new TObject(); + if ($lhs_type_part instanceof TUnknownClassString) { + $generated_type = $lhs_type_part->as_unknown_type ?? $generated_type; + } if ($lhs_type_part->as_type && $codebase->classlikes->classExists($lhs_type_part->as_type->value) @@ -834,7 +880,7 @@ class NewAnalyzer extends CallAnalyzer ); } - $new_type = Type::combineUnionTypes($new_type, new Union([$generated_type])); + $new_types []= new Union([$generated_type]); } continue; @@ -871,7 +917,7 @@ class NewAnalyzer extends CallAnalyzer ) { // do nothing } elseif ($lhs_type_part instanceof TNamedObject) { - $new_type = Type::combineUnionTypes($new_type, new Union([$lhs_type_part])); + $new_types []= new Union([$lhs_type_part]); continue; } else { IssueBuffer::maybeAdd( @@ -884,24 +930,12 @@ class NewAnalyzer extends CallAnalyzer ); } - $new_type = Type::combineUnionTypes($new_type, Type::getObject()); + $new_types []= Type::getObject(); } - if (!$has_single_class) { - if ($new_type) { - $statements_analyzer->node_data->setType($stmt, $new_type); - } - - ArgumentsAnalyzer::analyze( - $statements_analyzer, - $stmt->getArgs(), - null, - null, - true, - $context, - ); - - return; + if ($new_types) { + return Type::combineUnionTypeArray($new_types, $codebase); } + return null; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php index ccad64bb..0a604e08 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php @@ -3,6 +3,7 @@ namespace Psalm\Internal\Analyzer\Statements\Expression\Call\StaticMethod; use PhpParser; +use PhpParser\Node\Expr\StaticCall; use Psalm\CodeLocation; use Psalm\Codebase; use Psalm\Config; @@ -465,7 +466,7 @@ class ExistingAtomicStaticCallAnalyzer private static function getMethodReturnType( StatementsAnalyzer $statements_analyzer, Codebase $codebase, - PhpParser\Node\Expr\StaticCall $stmt, + StaticCall $stmt, MethodIdentifier $method_id, array $args, TemplateResult $template_result, @@ -493,40 +494,14 @@ class ExistingAtomicStaticCallAnalyzer [$template_type->param_name] [$template_type->defining_class], )) { - if ($template_type->param_name === 'TFunctionArgCount') { - $template_result->lower_bounds[$template_type->param_name] = [ - 'fn-' . strtolower((string)$method_id) => [ - new TemplateBound( - Type::getInt(false, count($stmt->getArgs())), - ), - ], - ]; - } elseif ($template_type->param_name === 'TPhpMajorVersion') { - $template_result->lower_bounds[$template_type->param_name] = [ - 'fn-' . strtolower((string)$method_id) => [ - new TemplateBound( - Type::getInt(false, $codebase->getMajorAnalysisPhpVersion()), - ), - ], - ]; - } elseif ($template_type->param_name === 'TPhpVersionId') { - $template_result->lower_bounds[$template_type->param_name] = [ - 'fn-' . strtolower((string) $method_id) => [ - new TemplateBound( - Type::getInt( - false, - $codebase->analysis_php_version_id, - ), - ), - ], - ]; - } else { - $template_result->lower_bounds[$template_type->param_name] = [ - ($template_type->defining_class) => [ - new TemplateBound(Type::getNever()), - ], - ]; - } + $template_result->lower_bounds[$template_type->param_name] + = self::resolveTemplateResultLowerBound( + $codebase, + $stmt, + $class_storage, + $method_id, + $template_type, + ); } } } @@ -632,4 +607,68 @@ class ExistingAtomicStaticCallAnalyzer $visitor->traverse($type); return $visitor->matches(); } + + /** + * @return non-empty-array> + */ + private static function resolveTemplateResultLowerBound( + Codebase $codebase, + StaticCall $stmt, + ClassLikeStorage $class_storage, + MethodIdentifier $method_id, + TTemplateParam $template_type + ): array { + if ($template_type->param_name === 'TFunctionArgCount') { + return [ + 'fn-' . strtolower((string)$method_id) => [ + new TemplateBound( + Type::getInt(false, count($stmt->getArgs())), + ), + ], + ]; + } + + if ($template_type->param_name === 'TPhpMajorVersion') { + return [ + 'fn-' . strtolower((string)$method_id) => [ + new TemplateBound( + Type::getInt(false, $codebase->getMajorAnalysisPhpVersion()), + ), + ], + ]; + } + + if ($template_type->param_name === 'TPhpVersionId') { + return [ + 'fn-' . strtolower((string) $method_id) => [ + new TemplateBound( + Type::getInt( + false, + $codebase->analysis_php_version_id, + ), + ), + ], + ]; + } + + if (isset( + $class_storage->template_extended_params[$template_type->defining_class][$template_type->param_name], + )) { + $extended_param_type = $class_storage->template_extended_params[ + $template_type->defining_class + ][$template_type->param_name]; + + return [ + ($template_type->defining_class) => [ + new TemplateBound($extended_param_type), + ], + ]; + } + + return [ + ($template_type->defining_class) => [ + new TemplateBound(Type::getNever()), + ], + ]; + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php index 5d072adb..348f528c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php @@ -42,6 +42,7 @@ use Psalm\Storage\Assertion\Truthy; use Psalm\Storage\ClassLikeStorage; use Psalm\Storage\Possibilities; use Psalm\Type; +use Psalm\Type\Atomic\TCallableObject; use Psalm\Type\Atomic\TNamedObject; use Psalm\Type\Atomic\TObjectWithProperties; use Psalm\Type\Atomic\TTemplateParam; @@ -579,6 +580,7 @@ class CallAnalyzer foreach ($type_part->extra_types as $extra_type) { if ($extra_type instanceof TTemplateParam || $extra_type instanceof TObjectWithProperties + || $extra_type instanceof TCallableObject ) { throw new UnexpectedValueException('Shouldn’t get a generic param here'); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php index d271ce94..0af910bd 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php @@ -844,6 +844,7 @@ class ClassConstAnalyzer assert($parent_classlike_storage !== null); if (!isset($parent_classlike_storage->parent_interfaces[strtolower($interface)]) && !isset($interface_storage->parent_interfaces[strtolower($parent_classlike_storage->name)]) + && $interface_const_storage !== $parent_const_storage ) { IssueBuffer::maybeAdd( new AmbiguousConstantInheritance( diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/EvalAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/EvalAnalyzer.php index e02ad2c6..34160e58 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/EvalAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/EvalAnalyzer.php @@ -26,7 +26,10 @@ class EvalAnalyzer PhpParser\Node\Expr\Eval_ $stmt, Context $context ): void { + $was_inside_call = $context->inside_call; + $context->inside_call = true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context); + $context->inside_call = $was_inside_call; $codebase = $statements_analyzer->getCodebase(); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php index 585d7ca1..66367938 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php @@ -115,17 +115,31 @@ class AtomicPropertyFetchAnalyzer return; } - $has_valid_fetch_type = true; + if ($lhs_type_part instanceof TObjectWithProperties) { + if (!isset($lhs_type_part->properties[$prop_name])) { + return; + } + + $has_valid_fetch_type = true; - if ($lhs_type_part instanceof TObjectWithProperties - && isset($lhs_type_part->properties[$prop_name]) - ) { $stmt_type = $statements_analyzer->node_data->getType($stmt); $statements_analyzer->node_data->setType( $stmt, Type::combineUnionTypes( - $lhs_type_part->properties[$prop_name], + TypeExpander::expandUnion( + $statements_analyzer->getCodebase(), + $lhs_type_part->properties[$prop_name], + null, + null, + null, + true, + true, + false, + true, + false, + true, + ), $stmt_type, ), ); @@ -133,12 +147,22 @@ class AtomicPropertyFetchAnalyzer return; } + $intersection_types = []; + if (!$lhs_type_part instanceof TObject) { + $intersection_types = $lhs_type_part->getIntersectionTypes(); + } + // stdClass and SimpleXMLElement are special cases where we cannot infer the return types // but we don't want to throw an error // Hack has a similar issue: https://github.com/facebook/hhvm/issues/5164 if ($lhs_type_part instanceof TObject - || in_array(strtolower($lhs_type_part->value), Config::getInstance()->getUniversalObjectCrates(), true) + || ( + in_array(strtolower($lhs_type_part->value), Config::getInstance()->getUniversalObjectCrates(), true) + && $intersection_types === [] + ) ) { + $has_valid_fetch_type = true; + $statements_analyzer->node_data->setType($stmt, Type::getMixed()); return; @@ -149,8 +173,6 @@ class AtomicPropertyFetchAnalyzer return; } - $intersection_types = $lhs_type_part->getIntersectionTypes() ?: []; - $fq_class_name = $lhs_type_part->value; $override_property_visibility = false; @@ -193,6 +215,7 @@ class AtomicPropertyFetchAnalyzer if ($class_storage->is_enum || in_array('UnitEnum', $codebase->getParentInterfaces($fq_class_name))) { if ($prop_name === 'value' && !$class_storage->is_enum) { + $has_valid_fetch_type = true; $statements_analyzer->node_data->setType( $stmt, new Union([ @@ -201,8 +224,10 @@ class AtomicPropertyFetchAnalyzer ]), ); } elseif ($prop_name === 'value' && $class_storage->enum_type !== null && $class_storage->enum_cases) { + $has_valid_fetch_type = true; self::handleEnumValue($statements_analyzer, $stmt, $stmt_var_type, $class_storage); } elseif ($prop_name === 'name') { + $has_valid_fetch_type = true; self::handleEnumName($statements_analyzer, $stmt, $lhs_type_part); } else { self::handleNonExistentProperty( @@ -220,6 +245,7 @@ class AtomicPropertyFetchAnalyzer $stmt_var_id, $has_magic_getter, $var_id, + $has_valid_fetch_type, ); } @@ -237,39 +263,60 @@ class AtomicPropertyFetchAnalyzer // add method before changing fq_class_name $get_method_id = new MethodIdentifier($fq_class_name, '__get'); - if (!$naive_property_exists - && $class_storage->namedMixins - ) { - foreach ($class_storage->namedMixins as $mixin) { - $new_property_id = $mixin->value . '::$' . $prop_name; + if (!$naive_property_exists) { + if ($class_storage->namedMixins) { + foreach ($class_storage->namedMixins as $mixin) { + $new_property_id = $mixin->value . '::$' . $prop_name; - try { - $new_class_storage = $codebase->classlike_storage_provider->get($mixin->value); - } catch (InvalidArgumentException $e) { - $new_class_storage = null; - } - - if ($new_class_storage - && ($codebase->properties->propertyExists( - $new_property_id, - !$in_assignment, - $statements_analyzer, - $context, - $codebase->collect_locations - ? new CodeLocation($statements_analyzer->getSource(), $stmt) - : null, - ) - || isset($new_class_storage->pseudo_property_get_types['$' . $prop_name])) - ) { - $fq_class_name = $mixin->value; - $lhs_type_part = $mixin; - $class_storage = $new_class_storage; - - if (!isset($new_class_storage->pseudo_property_get_types['$' . $prop_name])) { - $naive_property_exists = true; + try { + $new_class_storage = $codebase->classlike_storage_provider->get($mixin->value); + } catch (InvalidArgumentException $e) { + $new_class_storage = null; } - $property_id = $new_property_id; + if ($new_class_storage + && ($codebase->properties->propertyExists( + $new_property_id, + !$in_assignment, + $statements_analyzer, + $context, + $codebase->collect_locations + ? new CodeLocation($statements_analyzer->getSource(), $stmt) + : null, + ) + || isset($new_class_storage->pseudo_property_get_types['$' . $prop_name])) + ) { + $fq_class_name = $mixin->value; + $lhs_type_part = $mixin; + $class_storage = $new_class_storage; + + if (!isset($new_class_storage->pseudo_property_get_types['$' . $prop_name])) { + $naive_property_exists = true; + } + + $property_id = $new_property_id; + } + } + } elseif ($intersection_types !== [] && !$class_storage->final) { + foreach ($intersection_types as $intersection_type) { + self::analyze( + $statements_analyzer, + $stmt, + $context, + $in_assignment, + $var_id, + $stmt_var_id, + $stmt_var_type, + $intersection_type, + $prop_name, + $has_valid_fetch_type, + $invalid_fetch_types, + $is_static_access, + ); + + if ($has_valid_fetch_type) { + return; + } } } } @@ -350,6 +397,7 @@ class AtomicPropertyFetchAnalyzer $stmt_var_id, $has_magic_getter, $var_id, + $has_valid_fetch_type, ); return; @@ -485,6 +533,8 @@ class AtomicPropertyFetchAnalyzer } $stmt_type = $statements_analyzer->node_data->getType($stmt); + + $has_valid_fetch_type = true; $statements_analyzer->node_data->setType( $stmt, Type::combineUnionTypes($class_property_type, $stmt_type), @@ -663,7 +713,7 @@ class AtomicPropertyFetchAnalyzer * If we have an explicit list of all allowed magic properties on the class, and we're * not in that list, fall through */ - if (!($class_storage->sealed_properties || $codebase->config->seal_all_properties) + if (!($class_storage->hasSealedProperties($codebase->config)) && !$override_property_visibility ) { return false; @@ -1144,9 +1194,11 @@ class AtomicPropertyFetchAnalyzer bool $in_assignment, ?string $stmt_var_id, bool $has_magic_getter, - ?string $var_id + ?string $var_id, + bool &$has_valid_fetch_type ): void { - if ($config->use_phpdoc_property_without_magic_or_parent + if (($config->use_phpdoc_property_without_magic_or_parent + || $class_storage->hasAttributeIncludingParents('AllowDynamicProperties', $codebase)) && isset($class_storage->pseudo_property_get_types['$' . $prop_name]) ) { $stmt_type = $class_storage->pseudo_property_get_types['$' . $prop_name]; @@ -1178,6 +1230,7 @@ class AtomicPropertyFetchAnalyzer $context, ); + $has_valid_fetch_type = true; $statements_analyzer->node_data->setType($stmt, $stmt_type); return; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php index 1b6ad40f..cfa4326c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php @@ -158,7 +158,8 @@ class IncludeAnalyzer $current_file_analyzer = $statements_analyzer->getFileAnalyzer(); - if ($current_file_analyzer->project_analyzer->fileExists($path_to_file)) { + if ($current_file_analyzer->project_analyzer->fileExists($path_to_file) + && !$current_file_analyzer->project_analyzer->isDirectory($path_to_file)) { if ($statements_analyzer->hasParentFilePath($path_to_file) || !$codebase->file_storage_provider->has($path_to_file) || ($statements_analyzer->hasAlreadyRequiredFilePath($path_to_file) @@ -395,6 +396,18 @@ class IncludeAnalyzer return $file_name; } + if ((substr($file_name, 0, 2) === '.' . DIRECTORY_SEPARATOR) + || (substr($file_name, 0, 3) === '..' . DIRECTORY_SEPARATOR) + ) { + $file = $current_directory . DIRECTORY_SEPARATOR . $file_name; + + if (file_exists($file)) { + return $file; + } + + return null; + } + $paths = PATH_SEPARATOR === ':' ? preg_split('#(?cond->getAttributes(), ); } - } elseif ($stmt->cond instanceof PhpParser\Node\Expr\FuncCall - || $stmt->cond instanceof PhpParser\Node\Expr\MethodCall - || $stmt->cond instanceof PhpParser\Node\Expr\StaticCall + } elseif ($stmt->cond instanceof PhpParser\Node\Expr\ClassConstFetch + && $stmt->cond->name instanceof PhpParser\Node\Identifier + && $stmt->cond->name->toString() === 'class' ) { + // do nothing + } elseif ($stmt->cond instanceof PhpParser\Node\Expr\ConstFetch + && $stmt->cond->name->toString() === 'true' + ) { + // do nothing + } else { $switch_var_id = '$__tmp_switch__' . (int) $stmt->cond->getAttribute('startFilePos'); $condition_type = $statements_analyzer->node_data->getType($stmt->cond) ?? Type::getMixed(); @@ -128,18 +134,27 @@ class MatchAnalyzer } $arms = $stmt->arms; + $flattened_arms = []; + $last_arm = null; - foreach ($arms as $i => $arm) { - // move default to the end + foreach ($arms as $arm) { if ($arm->conds === null) { - unset($arms[$i]); - $arms[] = $arm; + $last_arm = $arm; + continue; + } + + foreach ($arm->conds as $cond) { + $flattened_arms[] = new PhpParser\Node\MatchArm( + [$cond], + $arm->body, + $arm->getAttributes(), + ); } } + $arms = $flattened_arms; $arms = array_reverse($arms); - - $last_arm = array_shift($arms); + $last_arm ??= array_shift($arms); if (!$last_arm) { IssueBuffer::maybeAdd( diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php index aa229281..3ba14ca6 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php @@ -666,17 +666,22 @@ class SimpleTypeInferer } elseif ($key_type->isSingleIntLiteral()) { $item_key_value = $key_type->getSingleIntLiteral()->value; - if ($item_key_value >= $array_creation_info->int_offset) { - if ($item_key_value === $array_creation_info->int_offset) { + if ($item_key_value <= PHP_INT_MAX + && $item_key_value > $array_creation_info->int_offset + ) { + if ($item_key_value - 1 === $array_creation_info->int_offset) { $item_is_list_item = true; } - $array_creation_info->int_offset = $item_key_value + 1; + $array_creation_info->int_offset = $item_key_value; } } } } else { + if ($array_creation_info->int_offset === PHP_INT_MAX) { + return false; + } $item_is_list_item = true; - $item_key_value = $array_creation_info->int_offset++; + $item_key_value = ++$array_creation_info->int_offset; $array_creation_info->item_key_atomic_types[] = new TLiteralInt($item_key_value); } @@ -760,7 +765,10 @@ class SimpleTypeInferer $new_offset = $key; $array_creation_info->item_key_atomic_types[] = Type::getAtomicStringFromLiteral($new_offset); } else { - $new_offset = $array_creation_info->int_offset++; + if ($array_creation_info->int_offset === PHP_INT_MAX) { + return false; + } + $new_offset = ++$array_creation_info->int_offset; $array_creation_info->item_key_atomic_types[] = new TLiteralInt($new_offset); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php index 0a946a36..7cdb1b54 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php @@ -53,6 +53,7 @@ use Psalm\Issue\UnrecognizedExpression; use Psalm\Issue\UnsupportedReferenceUsage; use Psalm\IssueBuffer; use Psalm\Plugin\EventHandler\Event\AfterExpressionAnalysisEvent; +use Psalm\Plugin\EventHandler\Event\BeforeExpressionAnalysisEvent; use Psalm\Storage\FunctionLikeParameter; use Psalm\Type; use Psalm\Type\TaintKind; @@ -80,6 +81,10 @@ class ExpressionAnalyzer ?TemplateResult $template_result = null, bool $assigned_to_reference = false ): bool { + if (self::dispatchBeforeExpressionAnalysis($stmt, $context, $statements_analyzer) === false) { + return false; + } + $codebase = $statements_analyzer->getCodebase(); if (self::handleExpression( @@ -126,24 +131,10 @@ class ExpressionAnalyzer } } - $event = new AfterExpressionAnalysisEvent( - $stmt, - $context, - $statements_analyzer, - $codebase, - [], - ); - - if ($codebase->config->eventDispatcher->dispatchAfterExpressionAnalysis($event) === false) { + if (self::dispatchAfterExpressionAnalysis($stmt, $context, $statements_analyzer) === false) { return false; } - $file_manipulations = $event->getFileReplacements(); - - if ($file_manipulations) { - FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); - } - return true; } @@ -280,7 +271,7 @@ class ExpressionAnalyzer } if ($stmt instanceof PhpParser\Node\Expr\New_) { - return NewAnalyzer::analyze($statements_analyzer, $stmt, $context); + return NewAnalyzer::analyze($statements_analyzer, $stmt, $context, $template_result); } if ($stmt instanceof PhpParser\Node\Expr\Array_) { @@ -554,4 +545,60 @@ class ExpressionAnalyzer return true; } + + private static function dispatchBeforeExpressionAnalysis( + PhpParser\Node\Expr $expr, + Context $context, + StatementsAnalyzer $statements_analyzer + ): ?bool { + $codebase = $statements_analyzer->getCodebase(); + + $event = new BeforeExpressionAnalysisEvent( + $expr, + $context, + $statements_analyzer, + $codebase, + [], + ); + + if ($codebase->config->eventDispatcher->dispatchBeforeExpressionAnalysis($event) === false) { + return false; + } + + $file_manipulations = $event->getFileReplacements(); + + if ($file_manipulations !== []) { + FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); + } + + return null; + } + + private static function dispatchAfterExpressionAnalysis( + PhpParser\Node\Expr $expr, + Context $context, + StatementsAnalyzer $statements_analyzer + ): ?bool { + $codebase = $statements_analyzer->getCodebase(); + + $event = new AfterExpressionAnalysisEvent( + $expr, + $context, + $statements_analyzer, + $codebase, + [], + ); + + if ($codebase->config->eventDispatcher->dispatchAfterExpressionAnalysis($event) === false) { + return false; + } + + $file_manipulations = $event->getFileReplacements(); + + if ($file_manipulations !== []) { + FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); + } + + return null; + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php index 896f5ac3..2b43d085 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php @@ -496,6 +496,7 @@ class StatementsAnalyzer extends SourceAnalyzer && !($stmt instanceof PhpParser\Node\Stmt\Interface_) && !($stmt instanceof PhpParser\Node\Stmt\Trait_) && !($stmt instanceof PhpParser\Node\Stmt\HaltCompiler) + && !($stmt instanceof PhpParser\Node\Stmt\Declare_) ) { if ($codebase->find_unused_variables) { IssueBuffer::maybeAdd( diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Cli/LanguageServer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Cli/LanguageServer.php index d9df6548..429144b6 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Cli/LanguageServer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Cli/LanguageServer.php @@ -2,20 +2,14 @@ namespace Psalm\Internal\Cli; +use LanguageServerProtocol\MessageType; use Psalm\Config; -use Psalm\Internal\Analyzer\ProjectAnalyzer; use Psalm\Internal\CliUtils; -use Psalm\Internal\Composer; use Psalm\Internal\ErrorHandler; use Psalm\Internal\Fork\PsalmRestarter; use Psalm\Internal\IncludeCollector; -use Psalm\Internal\Provider\ClassLikeStorageCacheProvider; -use Psalm\Internal\Provider\FileProvider; -use Psalm\Internal\Provider\FileReferenceCacheProvider; -use Psalm\Internal\Provider\FileStorageCacheProvider; -use Psalm\Internal\Provider\ParserCacheProvider; -use Psalm\Internal\Provider\ProjectCacheProvider; -use Psalm\Internal\Provider\Providers; +use Psalm\Internal\LanguageServer\ClientConfiguration; +use Psalm\Internal\LanguageServer\LanguageServer as LanguageServerLanguageServer; use Psalm\Report; use function array_key_exists; @@ -52,16 +46,21 @@ require_once __DIR__ . '/../ErrorHandler.php'; require_once __DIR__ . '/../CliUtils.php'; require_once __DIR__ . '/../Composer.php'; require_once __DIR__ . '/../IncludeCollector.php'; +require_once __DIR__ . '/../LanguageServer/ClientConfiguration.php'; /** * @internal */ final class LanguageServer { - /** @param array $argv */ + /** + * @param array $argv + * @psalm-suppress ComplexMethod + */ public static function run(array $argv): void { CliUtils::checkRuntimeRequirements(); + $clientConfiguration = new ClientConfiguration(); gc_disable(); ErrorHandler::install($argv); $valid_short_options = [ @@ -72,7 +71,6 @@ final class LanguageServer ]; $valid_long_options = [ - 'clear-cache', 'config:', 'find-dead-code', 'help', @@ -82,7 +80,17 @@ final class LanguageServer 'tcp:', 'tcp-server', 'disable-on-change::', + 'use-baseline:', 'enable-autocomplete::', + 'enable-code-actions::', + 'enable-provide-diagnostics::', + 'enable-provide-hover::', + 'enable-provide-signature-help::', + 'enable-provide-definition::', + 'show-diagnostic-warnings::', + 'in-memory::', + 'disable-xdebug::', + 'on-change-debounce-ms::', 'use-extended-diagnostic-codes', 'verbose', ]; @@ -164,12 +172,12 @@ final class LanguageServer --find-dead-code Look for dead code - --clear-cache - Clears all cache files that the language server uses for this specific project - --use-ini-defaults Use PHP-provided ini defaults for memory and error display + --use-baseline=PATH + Allows you to use a baseline other than the default baseline provided in your config + --tcp=url Use TCP mode (by default Psalm uses STDIO) @@ -180,12 +188,39 @@ final class LanguageServer If added, the language server will not respond to onChange events. You can also specify a line count over which Psalm will not run on-change events. + --enable-code-actions[=BOOL] + Enables or disables code actions. Default is true. + + --enable-provide-diagnostics[=BOOL] + Enables or disables providing diagnostics. Default is true. + --enable-autocomplete[=BOOL] Enables or disables autocomplete on methods and properties. Default is true. - --use-extended-diagnostic-codes + --enable-provide-hover[=BOOL] + Enables or disables providing hover. Default is true. + + --enable-provide-signature-help[=BOOL] + Enables or disables providing signature help. Default is true. + + --enable-provide-definition[=BOOL] + Enables or disables providing definition. Default is true. + + --show-diagnostic-warnings[=BOOL] + Enables or disables showing diagnostic warnings. Default is true. + + --use-extended-diagnostic-codes (DEPRECATED) Enables sending help uri links with the code in diagnostic messages. + --on-change-debounce-ms=[INT] + The number of milliseconds to debounce onChange events. + + --disable-xdebug[=BOOL] + Disable xdebug for performance reasons. Enable for debugging + + --in-memory[=BOOL] + Use in-memory mode. Default is false. Experimental. + --verbose Will send log messages to the client with information. @@ -245,8 +280,14 @@ final class LanguageServer 'blackfire', ]); - // If Xdebug is enabled, restart without it - $ini_handler->check(); + $disableXdebug = !isset($options['disable-xdebug']) + || !is_string($options['disable-xdebug']) + || strtolower($options['disable-xdebug']) !== 'false'; + + // If Xdebug is enabled, restart without it based on cli + if ($disableXdebug) { + $ini_handler->check(); + } setlocale(LC_CTYPE, 'C'); @@ -259,8 +300,6 @@ final class LanguageServer } } - $find_unused_code = isset($options['find-dead-code']) ? 'auto' : null; - $config = CliUtils::initializeConfig( $path_to_config, $current_dir, @@ -276,58 +315,85 @@ final class LanguageServer $config->setServerMode(); - if (isset($options['clear-cache'])) { + $inMemory = isset($options['in-memory']) && + is_string($options['in-memory']) && + strtolower($options['in-memory']) === 'true'; + + if ($inMemory) { + $config->cache_directory = null; + } else { $cache_directory = $config->getCacheDirectory(); if ($cache_directory !== null) { Config::removeCacheDirectory($cache_directory); } - echo 'Cache directory deleted' . PHP_EOL; - exit; } - $providers = new Providers( - new FileProvider, - new ParserCacheProvider($config), - new FileStorageCacheProvider($config), - new ClassLikeStorageCacheProvider($config), - new FileReferenceCacheProvider($config), - new ProjectCacheProvider(Composer::getLockFilePath($current_dir)), - ); - - $project_analyzer = new ProjectAnalyzer( - $config, - $providers, - ); - - if ($config->find_unused_variables) { - $project_analyzer->getCodebase()->reportUnusedVariables(); - } - - if ($config->find_unused_code) { - $find_unused_code = 'auto'; + if (isset($options['use-baseline']) && is_string($options['use-baseline'])) { + $clientConfiguration->baseline = $options['use-baseline']; } if (isset($options['disable-on-change']) && is_numeric($options['disable-on-change'])) { - $project_analyzer->onchange_line_limit = (int) $options['disable-on-change']; + $clientConfiguration->onchangeLineLimit = (int) $options['disable-on-change']; } - $project_analyzer->provide_completion = !isset($options['enable-autocomplete']) + if (isset($options['on-change-debounce-ms']) && is_numeric($options['on-change-debounce-ms'])) { + $clientConfiguration->onChangeDebounceMs = (int) $options['on-change-debounce-ms']; + } + + $clientConfiguration->provideDefinition = !isset($options['enable-provide-definition']) + || !is_string($options['enable-provide-definition']) + || strtolower($options['enable-provide-definition']) !== 'false'; + + $clientConfiguration->provideSignatureHelp = !isset($options['enable-provide-signature-help']) + || !is_string($options['enable-provide-signature-help']) + || strtolower($options['enable-provide-signature-help']) !== 'false'; + + $clientConfiguration->provideHover = !isset($options['enable-provide-hover']) + || !is_string($options['enable-provide-hover']) + || strtolower($options['enable-provide-hover']) !== 'false'; + + $clientConfiguration->provideDiagnostics = !isset($options['enable-provide-diagnostics']) + || !is_string($options['enable-provide-diagnostics']) + || strtolower($options['enable-provide-diagnostics']) !== 'false'; + + $clientConfiguration->provideCodeActions = !isset($options['enable-code-actions']) + || !is_string($options['enable-code-actions']) + || strtolower($options['enable-code-actions']) !== 'false'; + + $clientConfiguration->provideCompletion = !isset($options['enable-autocomplete']) || !is_string($options['enable-autocomplete']) || strtolower($options['enable-autocomplete']) !== 'false'; - if ($find_unused_code) { - $project_analyzer->getCodebase()->reportUnusedCode($find_unused_code); - } + $clientConfiguration->hideWarnings = !( + !isset($options['show-diagnostic-warnings']) + || !is_string($options['show-diagnostic-warnings']) + || strtolower($options['show-diagnostic-warnings']) !== 'false' + ); - if (isset($options['use-extended-diagnostic-codes'])) { - $project_analyzer->language_server_use_extended_diagnostic_codes = true; + /** + * if ($config->find_unused_variables) { + * $project_analyzer->getCodebase()->reportUnusedVariables(); + * } + */ + + $find_unused_code = isset($options['find-dead-code']) ? 'auto' : null; + if ($config->find_unused_code) { + $find_unused_code = 'auto'; + } + if ($find_unused_code) { + $clientConfiguration->findUnusedCode = $find_unused_code; } if (isset($options['verbose'])) { - $project_analyzer->language_server_verbose = true; + $clientConfiguration->logLevel = $options['verbose'] ? MessageType::LOG : MessageType::INFO; + } else { + $clientConfiguration->logLevel = MessageType::INFO; } - $project_analyzer->server($options['tcp'] ?? null, isset($options['tcp-server'])); + $clientConfiguration->TCPServerAddress = $options['tcp'] ?? null; + $clientConfiguration->TCPServerMode = isset($options['tcp-server']); + + LanguageServerLanguageServer::run($config, $clientConfiguration, $current_dir, $inMemory); } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php b/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php index 58ce6d78..7401cd1e 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php @@ -57,15 +57,12 @@ use function getopt; use function implode; use function in_array; use function ini_get; -use function ini_set; use function is_array; use function is_numeric; -use function is_scalar; use function is_string; use function json_encode; use function max; use function microtime; -use function opcache_get_status; use function parse_url; use function preg_match; use function preg_replace; @@ -190,7 +187,7 @@ final class Psalm self::validateCliArguments($args); - self::setMemoryLimit($options); + CliUtils::setMemoryLimit($options); self::syncShortOptions($options); @@ -463,29 +460,6 @@ final class Psalm ); } - /** - * @param array> $options - */ - private static function setMemoryLimit(array $options): void - { - if (!array_key_exists('use-ini-defaults', $options)) { - ini_set('display_errors', 'stderr'); - ini_set('display_startup_errors', '1'); - - $memoryLimit = (8 * 1_024 * 1_024 * 1_024); - - if (array_key_exists('memory-limit', $options)) { - $memoryLimit = $options['memory-limit']; - - if (!is_scalar($memoryLimit)) { - throw new ConfigException('Invalid memory limit specified.'); - } - } - - ini_set('memory_limit', (string) $memoryLimit); - } - } - /** * @param array $args */ @@ -923,11 +897,7 @@ final class Psalm // If Xdebug is enabled, restart without it $ini_handler->check(); - if (!function_exists('opcache_get_status') - || !($opcache_status = opcache_get_status(false)) - || !isset($opcache_status['opcache_enabled']) - || !$opcache_status['opcache_enabled'] - ) { + if (!function_exists('opcache_get_status')) { $progress->write(PHP_EOL . 'Install the opcache extension to make use of JIT on PHP 8.0+ for a 20%+ performance boost!' . PHP_EOL . PHP_EOL); @@ -1273,6 +1243,9 @@ final class Psalm --php-version=PHP_VERSION Explicitly set PHP version to analyse code against. + --error-level=ERROR_LEVEL + Set the error reporting level + Surfacing issues: --show-info[=BOOLEAN] Show non-exception parser findings (defaults to false). diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalter.php b/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalter.php index 6d5dfa0c..9dd8eaf4 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalter.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalter.php @@ -43,7 +43,6 @@ use function getcwd; use function getopt; use function implode; use function in_array; -use function ini_set; use function is_array; use function is_dir; use function is_numeric; @@ -89,6 +88,7 @@ final class Psalter 'add-newline-between-docblock-annotations:', 'no-cache', 'no-progress', + 'memory-limit:', ]; /** @param array $argv */ @@ -100,8 +100,6 @@ final class Psalter ErrorHandler::install($argv); - self::setMemoryLimit(); - $args = array_slice($argv, 1); // get options from command line @@ -109,6 +107,8 @@ final class Psalter self::validateCliArguments($args); + CliUtils::setMemoryLimit($options); + self::syncShortOptions($options); if (isset($options['c']) && is_array($options['c'])) { @@ -442,15 +442,6 @@ final class Psalter IssueBuffer::finish($project_analyzer, false, $start_time); } - private static function setMemoryLimit(): void - { - $memLimit = CliUtils::getMemoryLimitInBytes(); - // Magic number is 4096M in bytes - if ($memLimit > 0 && $memLimit < 8 * 1_024 * 1_024 * 1_024) { - ini_set('memory_limit', (string) (8 * 1_024 * 1_024 * 1_024)); - } - } - /** @param array $args */ private static function validateCliArguments(array $args): void { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/CliUtils.php b/vendor/vimeo/psalm/src/Psalm/Internal/CliUtils.php index fc1f979f..1e5a1abd 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/CliUtils.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/CliUtils.php @@ -14,8 +14,8 @@ use Psalm\Report; use RuntimeException; use function array_filter; +use function array_key_exists; use function array_slice; -use function assert; use function count; use function define; use function dirname; @@ -27,13 +27,13 @@ use function file_put_contents; use function fwrite; use function implode; use function in_array; -use function ini_get; +use function ini_set; use function is_array; use function is_dir; +use function is_scalar; use function is_string; use function json_decode; use function preg_last_error_msg; -use function preg_match; use function preg_replace; use function preg_split; use function realpath; @@ -41,7 +41,6 @@ use function stream_get_meta_data; use function stream_set_blocking; use function strlen; use function strpos; -use function strtoupper; use function substr; use function substr_replace; use function trim; @@ -446,38 +445,27 @@ final class CliUtils } /** - * @psalm-pure + * @param array> $options + * @throws ConfigException */ - public static function getMemoryLimitInBytes(): int + public static function setMemoryLimit(array $options): void { - return self::convertMemoryLimitToBytes(ini_get('memory_limit')); - } + if (!array_key_exists('use-ini-defaults', $options)) { + ini_set('display_errors', 'stderr'); + ini_set('display_startup_errors', '1'); - /** @psalm-pure */ - public static function convertMemoryLimitToBytes(string $limit): int - { - // for unlimited = -1 - if ($limit < 0) { - return -1; - } + $memoryLimit = (8 * 1_024 * 1_024 * 1_024); - if (preg_match('/^(\d+)(\D?)$/', $limit, $matches)) { - assert(isset($matches[1])); - $limit = (int)$matches[1]; - switch (strtoupper($matches[2] ?? '')) { - case 'G': - $limit *= 1_024 * 1_024 * 1_024; - break; - case 'M': - $limit *= 1_024 * 1_024; - break; - case 'K': - $limit *= 1_024; - break; + if (array_key_exists('memory-limit', $options)) { + $memoryLimit = $options['memory-limit']; + + if (!is_scalar($memoryLimit)) { + throw new ConfigException('Invalid memory limit specified.'); + } } - } - return (int)$limit; + ini_set('memory_limit', (string) $memoryLimit); + } } public static function initPhpVersion(array $options, Config $config, ProjectAnalyzer $project_analyzer): void diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassConstantByWildcardResolver.php b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassConstantByWildcardResolver.php index 97d3931b..0e6ef6f8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassConstantByWildcardResolver.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassConstantByWildcardResolver.php @@ -9,25 +9,23 @@ use Psalm\Type\Atomic; use Psalm\Type\Atomic\TMixed; use function array_merge; -use function array_values; -use function preg_match; -use function sprintf; -use function str_replace; /** * @internal */ final class ClassConstantByWildcardResolver { + private StorageByPatternResolver $resolver; private Codebase $codebase; public function __construct(Codebase $codebase) { + $this->resolver = new StorageByPatternResolver(); $this->codebase = $codebase; } /** - * @return list|null + * @return non-empty-array|null */ public function resolve(string $class_name, string $constant_pattern): ?array { @@ -35,24 +33,27 @@ final class ClassConstantByWildcardResolver return null; } - $constant_regex_pattern = sprintf('#^%s$#', str_replace('*', '.*', $constant_pattern)); + $classlike_storage = $this->codebase->classlike_storage_provider->get($class_name); - $class_like_storage = $this->codebase->classlike_storage_provider->get($class_name); - $matched_class_constant_types = []; - - foreach ($class_like_storage->constants as $constant => $class_constant_storage) { - if (preg_match($constant_regex_pattern, $constant) === 0) { - continue; - } + $constants = $this->resolver->resolveConstants( + $classlike_storage, + $constant_pattern, + ); + $types = []; + foreach ($constants as $class_constant_storage) { if (! $class_constant_storage->type) { - $matched_class_constant_types[] = [new TMixed()]; + $types[] = [new TMixed()]; continue; } - $matched_class_constant_types[] = $class_constant_storage->type->getAtomicTypes(); + $types[] = $class_constant_storage->type->getAtomicTypes(); } - return array_values(array_merge([], ...$matched_class_constant_types)); + if ($types === []) { + return null; + } + + return array_merge([], ...$types); } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassLikes.php b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassLikes.php index 618ba707..696b0413 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassLikes.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassLikes.php @@ -47,6 +47,7 @@ use ReflectionProperty; use UnexpectedValueException; use function array_filter; +use function array_keys; use function array_merge; use function array_pop; use function count; @@ -1603,8 +1604,7 @@ class ClassLikes } /** - * @param ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PROTECTED|ReflectionProperty::IS_PRIVATE - * $visibility + * @param ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PROTECTED|ReflectionProperty::IS_PRIVATE $visibility */ public function getClassConstantType( string $class_name, @@ -1612,7 +1612,8 @@ class ClassLikes int $visibility, ?StatementsAnalyzer $statements_analyzer = null, array $visited_constant_ids = [], - bool $late_static_binding = false + bool $late_static_binding = false, + bool $in_value_of_context = false ): ?Union { $class_name = strtolower($class_name); @@ -1622,41 +1623,42 @@ class ClassLikes $storage = $this->classlike_storage_provider->get($class_name); - if (isset($storage->constants[$constant_name])) { - $constant_storage = $storage->constants[$constant_name]; + $enum_types = null; - if ($visibility === ReflectionProperty::IS_PUBLIC - && $constant_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PUBLIC - ) { - return null; + if ($storage->is_enum) { + $enum_types = $this->getEnumType( + $storage, + $constant_name, + ); + + if ($in_value_of_context) { + return $enum_types; } - - if ($visibility === ReflectionProperty::IS_PROTECTED - && $constant_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PUBLIC - && $constant_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PROTECTED - ) { - return null; - } - - if ($constant_storage->unresolved_node) { - /** @psalm-suppress InaccessibleProperty Lazy resolution */ - $constant_storage->inferred_type = new Union([ConstantTypeResolver::resolve( - $this, - $constant_storage->unresolved_node, - $statements_analyzer, - $visited_constant_ids, - )]); - if ($constant_storage->type === null || !$constant_storage->type->from_docblock) { - /** @psalm-suppress InaccessibleProperty Lazy resolution */ - $constant_storage->type = $constant_storage->inferred_type; - } - } - - return $late_static_binding ? $constant_storage->type : ($constant_storage->inferred_type ?? null); - } elseif (isset($storage->enum_cases[$constant_name])) { - return new Union([new TEnumCase($storage->name, $constant_name)]); } - return null; + + $constant_types = $this->getConstantType( + $storage, + $constant_name, + $visibility, + $statements_analyzer, + $visited_constant_ids, + $late_static_binding, + ); + + $types = []; + if ($enum_types !== null) { + $types = array_merge($types, $enum_types->getAtomicTypes()); + } + + if ($constant_types !== null) { + $types = array_merge($types, $constant_types->getAtomicTypes()); + } + + if ($types === []) { + return null; + } + + return new Union($types); } private function checkMethodReferences(ClassLikeStorage $classlike_storage, Methods $methods): void @@ -2366,4 +2368,113 @@ class ClassLikes return null; } } + + private function getConstantType( + ClassLikeStorage $class_like_storage, + string $constant_name, + int $visibility, + ?StatementsAnalyzer $statements_analyzer, + array $visited_constant_ids, + bool $late_static_binding + ): ?Union { + $constant_resolver = new StorageByPatternResolver(); + $resolved_constants = $constant_resolver->resolveConstants( + $class_like_storage, + $constant_name, + ); + + $filtered_constants_by_visibility = array_filter( + $resolved_constants, + fn(ClassConstantStorage $resolved_constant) => $this->filterConstantNameByVisibility( + $resolved_constant, + $visibility, + ) + ); + + if ($filtered_constants_by_visibility === []) { + return null; + } + + $new_atomic_types = []; + + foreach ($filtered_constants_by_visibility as $filtered_constant_name => $constant_storage) { + if (!isset($class_like_storage->constants[$filtered_constant_name])) { + continue; + } + + if ($constant_storage->unresolved_node) { + /** @psalm-suppress InaccessibleProperty Lazy resolution */ + $constant_storage->inferred_type = new Union([ConstantTypeResolver::resolve( + $this, + $constant_storage->unresolved_node, + $statements_analyzer, + $visited_constant_ids, + )]); + + if ($constant_storage->type === null || !$constant_storage->type->from_docblock) { + /** @psalm-suppress InaccessibleProperty Lazy resolution */ + $constant_storage->type = $constant_storage->inferred_type; + } + } + + $constant_type = $late_static_binding + ? $constant_storage->type + : ($constant_storage->inferred_type ?? null); + + if ($constant_type === null) { + continue; + } + + $new_atomic_types[] = $constant_type->getAtomicTypes(); + } + + if ($new_atomic_types === []) { + return null; + } + + return new Union(array_merge([], ...$new_atomic_types)); + } + + private function getEnumType( + ClassLikeStorage $class_like_storage, + string $constant_name + ): ?Union { + $constant_resolver = new StorageByPatternResolver(); + $resolved_enums = $constant_resolver->resolveEnums( + $class_like_storage, + $constant_name, + ); + + if ($resolved_enums === []) { + return null; + } + + $types = []; + foreach (array_keys($resolved_enums) as $enum_case_name) { + $types[$enum_case_name] = new TEnumCase($class_like_storage->name, $enum_case_name); + } + + return new Union($types); + } + + private function filterConstantNameByVisibility( + ClassConstantStorage $constant_storage, + int $visibility + ): bool { + + if ($visibility === ReflectionProperty::IS_PUBLIC + && $constant_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PUBLIC + ) { + return false; + } + + if ($visibility === ReflectionProperty::IS_PROTECTED + && $constant_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PUBLIC + && $constant_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PROTECTED + ) { + return false; + } + + return true; + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ConstantTypeResolver.php b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ConstantTypeResolver.php index d341bbc9..9bf8caba 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ConstantTypeResolver.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ConstantTypeResolver.php @@ -11,6 +11,9 @@ use Psalm\Internal\Scanner\UnresolvedConstant\ArraySpread; use Psalm\Internal\Scanner\UnresolvedConstant\ArrayValue; use Psalm\Internal\Scanner\UnresolvedConstant\ClassConstant; use Psalm\Internal\Scanner\UnresolvedConstant\Constant; +use Psalm\Internal\Scanner\UnresolvedConstant\EnumNameFetch; +use Psalm\Internal\Scanner\UnresolvedConstant\EnumPropertyFetch; +use Psalm\Internal\Scanner\UnresolvedConstant\EnumValueFetch; use Psalm\Internal\Scanner\UnresolvedConstant\ScalarValue; use Psalm\Internal\Scanner\UnresolvedConstant\UnresolvedAdditionOp; use Psalm\Internal\Scanner\UnresolvedConstant\UnresolvedBinaryOp; @@ -331,6 +334,24 @@ class ConstantTypeResolver } } + if ($c instanceof EnumPropertyFetch) { + if ($classlikes->enumExists($c->fqcln)) { + $enum_storage = $classlikes->getStorageFor($c->fqcln); + if (isset($enum_storage->enum_cases[$c->case])) { + if ($c instanceof EnumValueFetch) { + $value = $enum_storage->enum_cases[$c->case]->value; + if (is_string($value)) { + return Type::getString($value)->getSingleAtomic(); + } elseif (is_int($value)) { + return Type::getInt(false, $value)->getSingleAtomic(); + } + } elseif ($c instanceof EnumNameFetch) { + return Type::getString($c->case)->getSingleAtomic(); + } + } + } + } + return new TMixed; } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Methods.php b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Methods.php index 802d41dc..a67a1d38 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Methods.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Methods.php @@ -825,8 +825,6 @@ class Methods return null; } - $candidate_type = null; - foreach ($class_storage->overridden_method_ids[$appearing_method_name] as $overridden_method_id) { $overridden_storage = $this->getStorage($overridden_method_id); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Populator.php b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Populator.php index a033401e..022cc684 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Populator.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Populator.php @@ -920,8 +920,8 @@ class Populator $fq_class_name = $storage->name; $fq_class_name_lc = strtolower($fq_class_name); - if ($parent_storage->sealed_methods) { - $storage->sealed_methods = true; + if ($parent_storage->sealed_methods !== null) { + $storage->sealed_methods = $parent_storage->sealed_methods; } // register where they appear (can never be in a trait) @@ -1032,8 +1032,8 @@ class Populator ClassLikeStorage $storage, ClassLikeStorage $parent_storage ): void { - if ($parent_storage->sealed_properties) { - $storage->sealed_properties = true; + if ($parent_storage->sealed_properties !== null) { + $storage->sealed_properties = $parent_storage->sealed_properties; } // register where they appear (can never be in a trait) diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Scanner.php b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Scanner.php index 0e215c32..ab2c586e 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Scanner.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Scanner.php @@ -291,6 +291,7 @@ class Scanner private function shouldScan(string $file_path): bool { return $this->file_provider->fileExists($file_path) + && !$this->file_provider->isDirectory($file_path) && (!isset($this->scanned_files[$file_path]) || (isset($this->files_to_deep_scan[$file_path]) && !$this->scanned_files[$file_path])); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/StorageByPatternResolver.php b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/StorageByPatternResolver.php new file mode 100644 index 00000000..ed5baed6 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/StorageByPatternResolver.php @@ -0,0 +1,87 @@ + + */ + public function resolveConstants( + ClassLikeStorage $class_like_storage, + string $pattern + ): array { + $constants = $class_like_storage->constants; + + if (strpos($pattern, '*') === false) { + if (isset($constants[$pattern])) { + return [$pattern => $constants[$pattern]]; + } + + return []; + } elseif ($pattern === '*') { + return $constants; + } + + $regex_pattern = sprintf('#^%s$#', str_replace('*', '.*?', $pattern)); + $matched_constants = []; + + foreach ($constants as $constant => $class_constant_storage) { + if (preg_match($regex_pattern, $constant) === 0) { + continue; + } + + $matched_constants[$constant] = $class_constant_storage; + } + + return $matched_constants; + } + + /** + * @return array + */ + public function resolveEnums( + ClassLikeStorage $class_like_storage, + string $pattern + ): array { + $enum_cases = $class_like_storage->enum_cases; + if (strpos($pattern, '*') === false) { + if (isset($enum_cases[$pattern])) { + return [$pattern => $enum_cases[$pattern]]; + } + + return []; + } elseif ($pattern === '*') { + return $enum_cases; + } + + $regex_pattern = sprintf('#^%s$#', str_replace('*', '.*?', $pattern)); + $matched_enums = []; + foreach ($enum_cases as $enum_case_name => $enum_case_storage) { + if (preg_match($regex_pattern, $enum_case_name) === 0) { + continue; + } + + $matched_enums[$enum_case_name] = $enum_case_storage; + } + + return $matched_enums; + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/EventDispatcher.php b/vendor/vimeo/psalm/src/Psalm/Internal/EventDispatcher.php index b42c7b3d..fb574949 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/EventDispatcher.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/EventDispatcher.php @@ -16,6 +16,7 @@ use Psalm\Plugin\EventHandler\AfterFunctionLikeAnalysisInterface; use Psalm\Plugin\EventHandler\AfterMethodCallAnalysisInterface; use Psalm\Plugin\EventHandler\AfterStatementAnalysisInterface; use Psalm\Plugin\EventHandler\BeforeAddIssueInterface; +use Psalm\Plugin\EventHandler\BeforeExpressionAnalysisInterface; use Psalm\Plugin\EventHandler\BeforeFileAnalysisInterface; use Psalm\Plugin\EventHandler\BeforeStatementAnalysisInterface; use Psalm\Plugin\EventHandler\Event\AddRemoveTaintsEvent; @@ -32,6 +33,7 @@ use Psalm\Plugin\EventHandler\Event\AfterFunctionLikeAnalysisEvent; use Psalm\Plugin\EventHandler\Event\AfterMethodCallAnalysisEvent; use Psalm\Plugin\EventHandler\Event\AfterStatementAnalysisEvent; use Psalm\Plugin\EventHandler\Event\BeforeAddIssueEvent; +use Psalm\Plugin\EventHandler\Event\BeforeExpressionAnalysisEvent; use Psalm\Plugin\EventHandler\Event\BeforeFileAnalysisEvent; use Psalm\Plugin\EventHandler\Event\BeforeStatementAnalysisEvent; use Psalm\Plugin\EventHandler\Event\StringInterpreterEvent; @@ -77,6 +79,13 @@ class EventDispatcher */ public array $after_every_function_checks = []; + /** + * Static methods to be called before expression checks are completed + * + * @var list> + */ + public array $before_expression_checks = []; + /** * Static methods to be called after expression checks have completed * @@ -197,6 +206,10 @@ class EventDispatcher $this->after_every_function_checks[] = $class; } + if (is_subclass_of($class, BeforeExpressionAnalysisInterface::class)) { + $this->before_expression_checks[] = $class; + } + if (is_subclass_of($class, AfterExpressionAnalysisInterface::class)) { $this->after_expression_checks[] = $class; } @@ -284,6 +297,17 @@ class EventDispatcher } } + public function dispatchBeforeExpressionAnalysis(BeforeExpressionAnalysisEvent $event): ?bool + { + foreach ($this->before_expression_checks as $handler) { + if ($handler::beforeExpressionAnalysis($event) === false) { + return false; + } + } + + return null; + } + public function dispatchAfterExpressionAnalysis(AfterExpressionAnalysisEvent $event): ?bool { foreach ($this->after_expression_checks as $handler) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/FileManipulation/FunctionDocblockManipulator.php b/vendor/vimeo/psalm/src/Psalm/Internal/FileManipulation/FunctionDocblockManipulator.php index 9b1762db..b04952c0 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/FileManipulation/FunctionDocblockManipulator.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/FileManipulation/FunctionDocblockManipulator.php @@ -137,7 +137,7 @@ class FunctionDocblockManipulator if ($param->type) { $this->param_typehint_offsets[$param->var->name] = [ (int) $param->type->getAttribute('startFilePos'), - (int) $param->type->getAttribute('endFilePos'), + (int) $param->type->getAttribute('endFilePos') + 1, ]; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Fork/PsalmRestarter.php b/vendor/vimeo/psalm/src/Psalm/Internal/Fork/PsalmRestarter.php index 32c255ca..27840944 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Fork/PsalmRestarter.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Fork/PsalmRestarter.php @@ -30,6 +30,7 @@ class PsalmRestarter extends XdebugHandler 'jit_buffer_size' => 512 * 1024 * 1024, 'optimization_level' => '0x7FFEBFFF', 'preload' => '', + 'log_verbosity_level' => 0, ]; private bool $required = false; @@ -70,6 +71,7 @@ class PsalmRestarter extends XdebugHandler $opcache_settings = [ 'enable_cli' => in_array(ini_get('opcache.enable_cli'), ['1', 'true', true, 1]), 'jit' => (int) ini_get('opcache.jit'), + 'log_verbosity_level' => (int) ini_get('opcache.log_verbosity_level'), 'optimization_level' => (string) ini_get('opcache.optimization_level'), 'preload' => (string) ini_get('opcache.preload'), 'jit_buffer_size' => self::toBytes(ini_get('opcache.jit_buffer_size')), @@ -146,6 +148,7 @@ class PsalmRestarter extends XdebugHandler '-dopcache.jit=1205', '-dopcache.optimization_level=0x7FFEBFFF', '-dopcache.preload=', + '-dopcache.log_verbosity_level=0', ]; } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/TextDocument.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/TextDocument.php index 2338465a..c7f4e378 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/TextDocument.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/TextDocument.php @@ -4,15 +4,9 @@ declare(strict_types=1); namespace Psalm\Internal\LanguageServer\Client; -use Amp\Promise; -use Generator; -use JsonMapper; use LanguageServerProtocol\Diagnostic; -use LanguageServerProtocol\TextDocumentIdentifier; -use LanguageServerProtocol\TextDocumentItem; use Psalm\Internal\LanguageServer\ClientHandler; - -use function Amp\call; +use Psalm\Internal\LanguageServer\LanguageServer; /** * Provides method handlers for all textDocument/* methods @@ -23,12 +17,12 @@ class TextDocument { private ClientHandler $handler; - private JsonMapper $mapper; + private LanguageServer $server; - public function __construct(ClientHandler $handler, JsonMapper $mapper) + public function __construct(ClientHandler $handler, LanguageServer $server) { $this->handler = $handler; - $this->mapper = $mapper; + $this->server = $server; } /** @@ -36,40 +30,18 @@ class TextDocument * * @param Diagnostic[] $diagnostics */ - public function publishDiagnostics(string $uri, array $diagnostics): void + public function publishDiagnostics(string $uri, array $diagnostics, ?int $version = null): void { + if (!$this->server->client->clientConfiguration->provideDiagnostics) { + return; + } + + $this->server->logDebug("textDocument/publishDiagnostics"); + $this->handler->notify('textDocument/publishDiagnostics', [ 'uri' => $uri, 'diagnostics' => $diagnostics, + 'version' => $version, ]); } - - /** - * The content request is sent from a server to a client - * to request the current content of a text document identified by the URI - * - * @param TextDocumentIdentifier $textDocument The document to get the content for - * @return Promise The document's current content - * @psalm-suppress MixedReturnTypeCoercion due to Psalm bug - */ - public function xcontent(TextDocumentIdentifier $textDocument): Promise - { - return call( - /** - * @return Generator, object, TextDocumentItem> - */ - function () use ($textDocument) { - /** @var Promise */ - $promise = $this->handler->request( - 'textDocument/xcontent', - ['textDocument' => $textDocument], - ); - - $result = yield $promise; - - /** @var TextDocumentItem */ - return $this->mapper->map($result, new TextDocumentItem); - }, - ); - } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Workspace.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Workspace.php new file mode 100644 index 00000000..f9d9cf39 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Client/Workspace.php @@ -0,0 +1,59 @@ +handler = $handler; + $this->mapper = $mapper; + $this->server = $server; + } + + /** + * The workspace/configuration request is sent from the server to the client to + * fetch configuration settings from the client. The request can fetch several + * configuration settings in one roundtrip. The order of the returned configuration + * settings correspond to the order of the passed ConfigurationItems (e.g. the first + * item in the response is the result for the first configuration item in the params). + * + * @param string $section The configuration section asked for. + * @param string|null $scopeUri The scope to get the configuration section for. + */ + public function requestConfiguration(string $section, ?string $scopeUri = null): Promise + { + $this->server->logDebug("workspace/configuration"); + + /** @var Promise */ + return $this->handler->request('workspace/configuration', [ + 'items' => [ + [ + 'section' => $section, + 'scopeUri' => $scopeUri, + ], + ], + ]); + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ClientConfiguration.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ClientConfiguration.php new file mode 100644 index 00000000..115a38f6 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ClientConfiguration.php @@ -0,0 +1,129 @@ +hideWarnings = $hideWarnings; + $this->provideCompletion = $provideCompletion; + $this->provideDefinition = $provideDefinition; + $this->provideHover = $provideHover; + $this->provideSignatureHelp = $provideSignatureHelp; + $this->provideCodeActions = $provideCodeActions; + $this->provideDiagnostics = $provideDiagnostics; + $this->findUnusedVariables = $findUnusedVariables; + $this->findUnusedCode = $findUnusedCode; + $this->logLevel = $logLevel; + $this->onchangeLineLimit = $onchangeLineLimit; + $this->baseline = $baseline; + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ClientHandler.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ClientHandler.php index 444e916b..06e48e3d 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ClientHandler.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ClientHandler.php @@ -13,7 +13,6 @@ use Amp\Promise; use Generator; use function Amp\call; -use function error_log; /** * @internal @@ -59,7 +58,6 @@ class ClientHandler $listener = function (Message $msg) use ($id, $deferred, &$listener): void { - error_log('request handler'); /** * @psalm-suppress UndefinedPropertyFetch * @psalm-suppress MixedArgument diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageClient.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageClient.php index 9a766dce..096177d9 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageClient.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageClient.php @@ -5,7 +5,14 @@ declare(strict_types=1); namespace Psalm\Internal\LanguageServer; use JsonMapper; +use LanguageServerProtocol\LogMessage; +use LanguageServerProtocol\LogTrace; use Psalm\Internal\LanguageServer\Client\TextDocument as ClientTextDocument; +use Psalm\Internal\LanguageServer\Client\Workspace as ClientWorkspace; + +use function is_null; +use function json_decode; +use function json_encode; /** * @internal @@ -17,44 +24,159 @@ class LanguageClient */ public ClientTextDocument $textDocument; + /** + * Handles workspace/* methods + */ + public ClientWorkspace $workspace; + /** * The client handler */ private ClientHandler $handler; - public function __construct(ProtocolReader $reader, ProtocolWriter $writer) - { - $this->handler = new ClientHandler($reader, $writer); - $mapper = new JsonMapper; + /** + * The Language Server + */ + private LanguageServer $server; - $this->textDocument = new ClientTextDocument($this->handler, $mapper); + /** + * The Client Configuration + */ + public ClientConfiguration $clientConfiguration; + + public function __construct( + ProtocolReader $reader, + ProtocolWriter $writer, + LanguageServer $server, + ClientConfiguration $clientConfiguration + ) { + $this->handler = new ClientHandler($reader, $writer); + $this->server = $server; + + $this->textDocument = new ClientTextDocument($this->handler, $this->server); + $this->workspace = new ClientWorkspace($this->handler, new JsonMapper, $this->server); + $this->clientConfiguration = $clientConfiguration; + } + + /** + * Request Configuration from Client and save it + */ + public function refreshConfiguration(): void + { + $capabilities = $this->server->clientCapabilities; + if ($capabilities && $capabilities->workspace && $capabilities->workspace->configuration) { + $this->workspace->requestConfiguration('psalm')->onResolve(function ($error, $value): void { + if ($error) { + $this->server->logError('There was an error getting configuration'); + } else { + /** @var array $value */ + [$config] = $value; + $this->configurationRefreshed((array) $config); + } + }); + } + } + + /** + * A notification to log the trace of the server’s execution. + * The amount and content of these notifications depends on the current trace configuration. + * + * @psalm-suppress PossiblyUnusedMethod + */ + public function logTrace(LogTrace $logTrace): void + { + //If trace is 'off', the server should not send any logTrace notification. + if (is_null($this->server->trace) || $this->server->trace === 'off') { + return; + } + + //If trace is 'messages', the server should not add the 'verbose' field in the LogTraceParams. + if ($this->server->trace === 'messages') { + $logTrace->verbose = null; + } + + $this->handler->notify( + '$/logTrace', + $logTrace, + ); } /** * Send a log message to the client. - * - * @param string $message The message to send to the client. - * @psalm-param 1|2|3|4 $type - * @param int $type The log type: - * - 1 = Error - * - 2 = Warning - * - 3 = Info - * - 4 = Log */ - public function logMessage(string $message, int $type = 4, string $method = 'window/logMessage'): void + public function logMessage(LogMessage $logMessage): void { - // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_logMessage - - if ($type < 1 || $type > 4) { - $type = 4; - } - $this->handler->notify( - $method, - [ - 'type' => $type, - 'message' => $message, - ], + 'window/logMessage', + $logMessage, ); } + + /** + * The telemetry notification is sent from the + * server to the client to ask the client to log + * a telemetry event. + * + * The protocol doesn’t specify the payload since no + * interpretation of the data happens in the protocol. + * Most clients even don’t handle the event directly + * but forward them to the extensions owing the corresponding + * server issuing the event. + */ + public function event(LogMessage $logMessage): void + { + $this->handler->notify( + 'telemetry/event', + $logMessage, + ); + } + + /** + * Configuration Refreshed from Client + * + * @param array $config + */ + private function configurationRefreshed(array $config): void + { + //do things when the config is refreshed + + if (empty($config)) { + return; + } + + /** @var array */ + $array = json_decode(json_encode($config), true); + + if (isset($array['hideWarnings'])) { + $this->clientConfiguration->hideWarnings = (bool) $array['hideWarnings']; + } + + if (isset($array['provideCompletion'])) { + $this->clientConfiguration->provideCompletion = (bool) $array['provideCompletion']; + } + + if (isset($array['provideDefinition'])) { + $this->clientConfiguration->provideDefinition = (bool) $array['provideDefinition']; + } + + if (isset($array['provideHover'])) { + $this->clientConfiguration->provideHover = (bool) $array['provideHover']; + } + + if (isset($array['provideSignatureHelp'])) { + $this->clientConfiguration->provideSignatureHelp = (bool) $array['provideSignatureHelp']; + } + + if (isset($array['provideCodeActions'])) { + $this->clientConfiguration->provideCodeActions = (bool) $array['provideCodeActions']; + } + + if (isset($array['provideDiagnostics'])) { + $this->clientConfiguration->provideDiagnostics = (bool) $array['provideDiagnostics']; + } + + if (isset($array['findUnusedVariables'])) { + $this->clientConfiguration->findUnusedVariables = (bool) $array['findUnusedVariables']; + } + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageServer.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageServer.php index 9784cd40..daec34e8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageServer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/LanguageServer.php @@ -11,16 +11,23 @@ use AdvancedJsonRpc\ErrorResponse; use AdvancedJsonRpc\Request; use AdvancedJsonRpc\Response; use AdvancedJsonRpc\SuccessResponse; +use Amp\Loop; use Amp\Promise; use Amp\Success; use Generator; use InvalidArgumentException; use JsonMapper; use LanguageServerProtocol\ClientCapabilities; +use LanguageServerProtocol\ClientInfo; +use LanguageServerProtocol\CodeDescription; use LanguageServerProtocol\CompletionOptions; use LanguageServerProtocol\Diagnostic; use LanguageServerProtocol\DiagnosticSeverity; +use LanguageServerProtocol\ExecuteCommandOptions; use LanguageServerProtocol\InitializeResult; +use LanguageServerProtocol\InitializeResultServerInfo; +use LanguageServerProtocol\LogMessage; +use LanguageServerProtocol\MessageType; use LanguageServerProtocol\Position; use LanguageServerProtocol\Range; use LanguageServerProtocol\SaveOptions; @@ -28,34 +35,68 @@ use LanguageServerProtocol\ServerCapabilities; use LanguageServerProtocol\SignatureHelpOptions; use LanguageServerProtocol\TextDocumentSyncKind; use LanguageServerProtocol\TextDocumentSyncOptions; +use Psalm\Codebase; use Psalm\Config; +use Psalm\ErrorBaseline; use Psalm\Internal\Analyzer\IssueData; use Psalm\Internal\Analyzer\ProjectAnalyzer; +use Psalm\Internal\Composer; +use Psalm\Internal\LanguageServer\Provider\ClassLikeStorageCacheProvider as InMemoryClassLikeStorageCacheProvider; +use Psalm\Internal\LanguageServer\Provider\FileReferenceCacheProvider as InMemoryFileReferenceCacheProvider; +use Psalm\Internal\LanguageServer\Provider\FileStorageCacheProvider as InMemoryFileStorageCacheProvider; +use Psalm\Internal\LanguageServer\Provider\ParserCacheProvider as InMemoryParserCacheProvider; +use Psalm\Internal\LanguageServer\Provider\ProjectCacheProvider as InMemoryProjectCacheProvider; use Psalm\Internal\LanguageServer\Server\TextDocument as ServerTextDocument; use Psalm\Internal\LanguageServer\Server\Workspace as ServerWorkspace; +use Psalm\Internal\Provider\ClassLikeStorageCacheProvider; +use Psalm\Internal\Provider\FileProvider; +use Psalm\Internal\Provider\FileReferenceCacheProvider; +use Psalm\Internal\Provider\FileStorageCacheProvider; +use Psalm\Internal\Provider\ParserCacheProvider; +use Psalm\Internal\Provider\ProjectCacheProvider; +use Psalm\Internal\Provider\Providers; use Psalm\IssueBuffer; use Throwable; use function Amp\asyncCoroutine; use function Amp\call; use function array_combine; +use function array_filter; use function array_keys; use function array_map; +use function array_reduce; +use function array_search; use function array_shift; +use function array_splice; use function array_unshift; +use function array_values; +use function cli_set_process_title; +use function count; use function explode; +use function fwrite; use function implode; +use function json_encode; use function max; use function parse_url; use function rawurlencode; use function realpath; use function str_replace; +use function stream_set_blocking; +use function stream_socket_accept; +use function stream_socket_client; +use function stream_socket_server; use function strpos; use function substr; use function trim; use function urldecode; +use const JSON_PRETTY_PRINT; +use const STDERR; +use const STDIN; +use const STDOUT; + /** + * @psalm-api * @internal */ class LanguageServer extends Dispatcher @@ -70,28 +111,29 @@ class LanguageServer extends Dispatcher */ public ?ServerWorkspace $workspace = null; + public ?ClientInfo $clientInfo = null; + protected ProtocolReader $protocolReader; protected ProtocolWriter $protocolWriter; public LanguageClient $client; + public ?ClientCapabilities $clientCapabilities = null; + + public ?string $trace = null; + protected ProjectAnalyzer $project_analyzer; - /** - * @var array - */ - protected array $onsave_paths_to_analyze = []; + protected Codebase $codebase; /** - * @var array + * The AMP Delay token */ - protected array $onchange_paths_to_analyze = []; + protected string $versionedAnalysisDelayToken = ''; - /** - * @var array> - */ - protected array $current_issues = []; + /** @var array}>> */ + protected array $issue_baseline = []; /** * This should actually be a private property on `parent` @@ -103,11 +145,19 @@ class LanguageServer extends Dispatcher public function __construct( ProtocolReader $reader, ProtocolWriter $writer, - ProjectAnalyzer $project_analyzer + ProjectAnalyzer $project_analyzer, + Codebase $codebase, + ClientConfiguration $clientConfiguration, + Progress $progress ) { parent::__construct($this, '/'); + + $progress->setServer($this); + $this->project_analyzer = $project_analyzer; + $this->codebase = $codebase; + $this->protocolWriter = $writer; $this->protocolReader = $reader; @@ -139,10 +189,14 @@ class LanguageServer extends Dispatcher try { // Invoke the method handler to get a result /** - * @var Promise + * @var Promise|null */ $dispatched = $this->dispatch($msg->body); - $result = yield $dispatched; + if ($dispatched !== null) { + $result = yield $dispatched; + } else { + $result = null; + } } catch (Error $e) { // If a ResponseError is thrown, send it back in the Response $error = $e; @@ -155,6 +209,9 @@ class LanguageServer extends Dispatcher $e, ); } + if ($error !== null) { + $this->logError($error->message); + } // Only send a Response for a Request // Notifications do not send Responses /** @@ -176,35 +233,171 @@ class LanguageServer extends Dispatcher $this->protocolReader->on( 'readMessageGroup', function (): void { - $this->doAnalysis(); + //$this->verboseLog('Received message group'); + //$this->doAnalysis(); }, ); - $this->client = new LanguageClient($reader, $writer); + $this->client = new LanguageClient($reader, $writer, $this, $clientConfiguration); - $this->verboseLog("Language server has started."); + $this->logInfo("Psalm Language Server ".PSALM_VERSION." has started."); + } + + /** + * Start the Server + */ + public static function run( + Config $config, + ClientConfiguration $clientConfiguration, + string $base_dir, + bool $inMemory = false + ): void { + $progress = new Progress(); + + if ($inMemory) { + $providers = new Providers( + new FileProvider, + new InMemoryParserCacheProvider, + new InMemoryFileStorageCacheProvider, + new InMemoryClassLikeStorageCacheProvider, + new InMemoryFileReferenceCacheProvider($config), + new InMemoryProjectCacheProvider, + ); + } else { + $providers = new Providers( + new FileProvider, + new ParserCacheProvider($config), + new FileStorageCacheProvider($config), + new ClassLikeStorageCacheProvider($config), + new FileReferenceCacheProvider($config), + new ProjectCacheProvider(Composer::getLockFilePath($base_dir)), + ); + } + + $codebase = new Codebase( + $config, + $providers, + $progress, + ); + + if ($config->find_unused_variables) { + $codebase->reportUnusedVariables(); + } + + if ($clientConfiguration->findUnusedCode) { + $codebase->reportUnusedCode($clientConfiguration->findUnusedCode); + } + + $project_analyzer = new ProjectAnalyzer( + $config, + $providers, + null, + [], + 1, + $progress, + $codebase, + ); + + if ($clientConfiguration->onchangeLineLimit) { + $project_analyzer->onchange_line_limit = $clientConfiguration->onchangeLineLimit; + } + + //Setup Project Analyzer + $project_analyzer->provide_completion = (bool) $clientConfiguration->provideCompletion; + + @cli_set_process_title('Psalm ' . PSALM_VERSION . ' - PHP Language Server'); + + if (!$clientConfiguration->TCPServerMode && $clientConfiguration->TCPServerAddress) { + // Connect to a TCP server + $socket = stream_socket_client('tcp://' . $clientConfiguration->TCPServerAddress, $errno, $errstr); + if ($socket === false) { + fwrite(STDERR, "Could not connect to language client. Error $errno\n$errstr"); + exit(1); + } + stream_set_blocking($socket, false); + new self( + new ProtocolStreamReader($socket), + new ProtocolStreamWriter($socket), + $project_analyzer, + $codebase, + $clientConfiguration, + $progress, + ); + Loop::run(); + } elseif ($clientConfiguration->TCPServerMode && $clientConfiguration->TCPServerAddress) { + // Run a TCP Server + $tcpServer = stream_socket_server('tcp://' . $clientConfiguration->TCPServerAddress, $errno, $errstr); + if ($tcpServer === false) { + fwrite(STDERR, "Could not listen on {$clientConfiguration->TCPServerAddress}. Error $errno\n$errstr"); + exit(1); + } + fwrite(STDOUT, "Server listening on {$clientConfiguration->TCPServerAddress}\n"); + + while ($socket = stream_socket_accept($tcpServer, -1)) { + fwrite(STDOUT, "Connection accepted\n"); + stream_set_blocking($socket, false); + //we only accept one connection. + //An exit notification will terminate the server + new LanguageServer( + new ProtocolStreamReader($socket), + new ProtocolStreamWriter($socket), + $project_analyzer, + $codebase, + $clientConfiguration, + $progress, + ); + Loop::run(); + } + } else { + // Use STDIO + stream_set_blocking(STDIN, false); + new LanguageServer( + new ProtocolStreamReader(STDIN), + new ProtocolStreamWriter(STDOUT), + $project_analyzer, + $codebase, + $clientConfiguration, + $progress, + ); + Loop::run(); + } } /** * The initialize request is sent as the first request from the client to the server. * * @param ClientCapabilities $capabilities The capabilities provided by the client (editor) - * @param string|null $rootPath The rootPath of the workspace. Is null if no folder is open. * @param int|null $processId The process Id of the parent process that started the server. * Is null if the process has not been started by another process. If the parent process is * not alive then the server should exit (see exit notification) its process. + * @param ClientInfo|null $clientInfo Information about the client + * @param string|null $locale The locale the client is currently showing the user interface + * in. This must not necessarily be the locale of the operating + * system. + * @param string|null $rootPath The rootPath of the workspace. Is null if no folder is open. + * @param mixed $initializationOptions + * @param string|null $trace The initial trace setting. If omitted trace is disabled ('off'). * @psalm-return Promise - * @psalm-suppress PossiblyUnusedMethod + * @psalm-suppress PossiblyUnusedParam */ public function initialize( ClientCapabilities $capabilities, + ?int $processId = null, + ?ClientInfo $clientInfo = null, + ?string $locale = null, ?string $rootPath = null, - ?int $processId = null + ?string $rootUri = null, + $initializationOptions = null, + ?string $trace = null + //?array $workspaceFolders = null //error in json-dispatcher ): Promise { + $this->clientInfo = $clientInfo; + $this->clientCapabilities = $capabilities; + $this->trace = $trace; return call( /** @return Generator */ - function (): Generator { - $this->verboseLog("Initializing..."); + function () { + $this->logInfo("Initializing..."); $this->clientStatus('initializing'); // Eventually, this might block on something. Leave it as a generator. @@ -213,22 +406,23 @@ class LanguageServer extends Dispatcher yield true; } - $this->verboseLog("Initializing: Getting code base..."); + $this->project_analyzer->serverMode($this); + + $this->logInfo("Initializing: Getting code base..."); $this->clientStatus('initializing', 'getting code base'); - $codebase = $this->project_analyzer->getCodebase(); - $this->verboseLog("Initializing: Scanning files..."); + $this->logInfo("Initializing: Scanning files ({$this->project_analyzer->threads} Threads)..."); $this->clientStatus('initializing', 'scanning files'); - $codebase->scanFiles($this->project_analyzer->threads); + $this->codebase->scanFiles($this->project_analyzer->threads); - $this->verboseLog("Initializing: Registering stub files..."); + $this->logInfo("Initializing: Registering stub files..."); $this->clientStatus('initializing', 'registering stub files'); - $codebase->config->visitStubFiles($codebase); + $this->codebase->config->visitStubFiles($this->codebase, $this->project_analyzer->progress); if ($this->textDocument === null) { $this->textDocument = new ServerTextDocument( $this, - $codebase, + $this->codebase, $this->project_analyzer, ); } @@ -236,199 +430,408 @@ class LanguageServer extends Dispatcher if ($this->workspace === null) { $this->workspace = new ServerWorkspace( $this, - $codebase, + $this->codebase, $this->project_analyzer, ); } $serverCapabilities = new ServerCapabilities(); + //The server provides execute command support. + $serverCapabilities->executeCommandProvider = new ExecuteCommandOptions(['test']); + $textDocumentSyncOptions = new TextDocumentSyncOptions(); + //Open and close notifications are sent to the server. $textDocumentSyncOptions->openClose = true; $saveOptions = new SaveOptions(); + //The client is supposed to include the content on save. $saveOptions->includeText = true; $textDocumentSyncOptions->save = $saveOptions; + /** + * Change notifications are sent to the server. See + * TextDocumentSyncKind.None, TextDocumentSyncKind.Full and + * TextDocumentSyncKind.Incremental. If omitted it defaults to + * TextDocumentSyncKind.None. + */ if ($this->project_analyzer->onchange_line_limit === 0) { + /** + * Documents should not be synced at all. + */ $textDocumentSyncOptions->change = TextDocumentSyncKind::NONE; } else { + /** + * Documents are synced by always sending the full content + * of the document. + */ $textDocumentSyncOptions->change = TextDocumentSyncKind::FULL; } + /** + * Defines how text documents are synced. Is either a detailed structure + * defining each notification or for backwards compatibility the + * TextDocumentSyncKind number. If omitted it defaults to + * `TextDocumentSyncKind.None`. + */ $serverCapabilities->textDocumentSync = $textDocumentSyncOptions; - // Support "Find all symbols" + /** + * The server provides document symbol support. + * Support "Find all symbols" + */ $serverCapabilities->documentSymbolProvider = false; - // Support "Find all symbols in workspace" + /** + * The server provides workspace symbol support. + * Support "Find all symbols in workspace" + */ $serverCapabilities->workspaceSymbolProvider = false; - // Support "Go to definition" + /** + * The server provides goto definition support. + * Support "Go to definition" + */ $serverCapabilities->definitionProvider = true; - // Support "Find all references" + /** + * The server provides find references support. + * Support "Find all references" + */ $serverCapabilities->referencesProvider = false; - // Support "Hover" + /** + * The server provides hover support. + * Support "Hover" + */ $serverCapabilities->hoverProvider = true; - // Support "Completion" - $serverCapabilities->codeActionProvider = true; - // Support "Code Actions" + /** + * The server provides completion support. + * Support "Completion" + */ if ($this->project_analyzer->provide_completion) { $serverCapabilities->completionProvider = new CompletionOptions(); + /** + * The server provides support to resolve additional + * information for a completion item. + */ $serverCapabilities->completionProvider->resolveProvider = false; + /** + * Most tools trigger completion request automatically without explicitly + * requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they + * do so when the user starts to type an identifier. For example if the user + * types `c` in a JavaScript file code complete will automatically pop up + * present `console` besides others as a completion item. Characters that + * make up identifiers don't need to be listed here. + * + * If code complete should automatically be trigger on characters not being + * valid inside an identifier (for example `.` in JavaScript) list them in + * `triggerCharacters`. + */ $serverCapabilities->completionProvider->triggerCharacters = ['$', '>', ':',"[", "(", ",", " "]; } + /** + * Whether code action supports the `data` property which is + * preserved between a `textDocument/codeAction` and a + * `codeAction/resolve` request. + * + * Support "Code Actions" if we support data + * + * @since LSP 3.16.0 + */ + if ($this->clientCapabilities && + $this->clientCapabilities->textDocument && + $this->clientCapabilities->textDocument->publishDiagnostics && + $this->clientCapabilities->textDocument->publishDiagnostics->dataSupport + ) { + $serverCapabilities->codeActionProvider = true; + } + + /** + * The server provides signature help support. + */ $serverCapabilities->signatureHelpProvider = new SignatureHelpOptions(['(', ',']); - // Support global references - $serverCapabilities->xworkspaceReferencesProvider = false; - $serverCapabilities->xdefinitionProvider = false; - $serverCapabilities->dependenciesProvider = false; + if ($this->client->clientConfiguration->baseline !== null) { + $this->logInfo('Utilizing Baseline: '.$this->client->clientConfiguration->baseline); + $this->issue_baseline= ErrorBaseline::read( + new FileProvider, + $this->client->clientConfiguration->baseline, + ); + } - $this->verboseLog("Initializing: Complete."); + $this->logInfo("Initializing: Complete."); $this->clientStatus('initialized'); - return new InitializeResult($serverCapabilities); + + /** + * Information about the server. + * + * @since LSP 3.15.0 + */ + $initializeResultServerInfo = new InitializeResultServerInfo('Psalm Language Server', PSALM_VERSION); + + return new InitializeResult($serverCapabilities, $initializeResultServerInfo); }, ); } /** - * @psalm-suppress PossiblyUnusedMethod + * The initialized notification is sent from the client to the server after the client received the result of the + * initialize request but before the client is sending any other request or notification to the server. + * The server can use the initialized notification for example to dynamically register capabilities. + * The initialized notification may only be sent once. */ public function initialized(): void { + try { + $this->client->refreshConfiguration(); + } catch (Throwable $e) { + $this->logError((string) $e); + } $this->clientStatus('running'); } - public function queueTemporaryFileAnalysis(string $file_path, string $uri): void - { - $this->onchange_paths_to_analyze[$file_path] = $uri; - } - - public function queueFileAnalysis(string $file_path, string $uri): void - { - $this->onsave_paths_to_analyze[$file_path] = $uri; - } - - public function doAnalysis(): void - { - $this->clientStatus('analyzing'); - - try { - $codebase = $this->project_analyzer->getCodebase(); - - $all_files_to_analyze = $this->onchange_paths_to_analyze + $this->onsave_paths_to_analyze; - - if (!$all_files_to_analyze) { - return; - } - - if ($this->onsave_paths_to_analyze) { - $codebase->reloadFiles($this->project_analyzer, array_keys($this->onsave_paths_to_analyze)); - } - - if ($this->onchange_paths_to_analyze) { - $codebase->reloadFiles($this->project_analyzer, array_keys($this->onchange_paths_to_analyze)); - } - - $all_file_paths_to_analyze = array_keys($all_files_to_analyze); - $codebase->analyzer->addFilesToAnalyze( - array_combine($all_file_paths_to_analyze, $all_file_paths_to_analyze), - ); - $codebase->analyzer->analyzeFiles($this->project_analyzer, 1, false); - - $this->emitIssues($all_files_to_analyze); - - $this->onchange_paths_to_analyze = []; - $this->onsave_paths_to_analyze = []; - } finally { - // we are done, so set the status back to running - $this->clientStatus('running'); - } - } - /** - * @param array $uris + * Queue Change File Analysis */ - public function emitIssues(array $uris): void + public function queueChangeFileAnalysis(string $file_path, string $uri, ?int $version = null): void { - $data = IssueBuffer::clear(); - $this->current_issues = $data; + $this->doVersionedAnalysisDebounce([$file_path => $uri], $version); + } - foreach ($uris as $file_path => $uri) { - $diagnostics = []; + /** + * Queue Open File Analysis + */ + public function queueOpenFileAnalysis(string $file_path, string $uri, ?int $version = null): void + { + $this->doVersionedAnalysis([$file_path => $uri], $version); + } - foreach (($data[$file_path] ?? []) as $issue_data) { - //$check_name = $issue->check_name; - $description = $issue_data->message; - $severity = $issue_data->severity; + /** + * Queue Closed File Analysis + */ + public function queueClosedFileAnalysis(string $file_path, string $uri): void + { + $this->doVersionedAnalysis([$file_path => $uri]); + } - $start_line = max($issue_data->line_from, 1); - $end_line = $issue_data->line_to; - $start_column = $issue_data->column_from; - $end_column = $issue_data->column_to; - // Language server has 0 based lines and columns, phan has 1-based lines and columns. - $range = new Range( - new Position($start_line - 1, $start_column - 1), - new Position($end_line - 1, $end_column - 1), - ); - switch ($severity) { - case Config::REPORT_INFO: - $diagnostic_severity = DiagnosticSeverity::WARNING; - break; - case Config::REPORT_ERROR: - default: - $diagnostic_severity = DiagnosticSeverity::ERROR; - break; - } - $diagnostic = new Diagnostic( - $description, - $range, - null, - $diagnostic_severity, - 'Psalm', - ); + /** + * Queue Saved File Analysis + */ + public function queueSaveFileAnalysis(string $file_path, string $uri): void + { + $this->queueFileAnalysisWithOpenedFiles([$file_path => $uri]); + } - //$code = 'PS' . \str_pad((string) $issue_data->shortcode, 3, "0", \STR_PAD_LEFT); - $code = $issue_data->link; + /** + * Queue File Analysis appending any opened files + * + * This allows for reanalysis of files that have been opened + * + * @param array $files + */ + public function queueFileAnalysisWithOpenedFiles(array $files = []): void + { + /** @var array $opened */ + $opened = array_reduce( + $this->project_analyzer->getCodebase()->file_provider->getOpenFilesPath(), + function (array $opened, string $file_path) { + $opened[$file_path] = $this->pathToUri($file_path); + return $opened; + }, + $files, + ); - if ($this->project_analyzer->language_server_use_extended_diagnostic_codes) { - // Added in VSCode 1.43.0 and will be part of the LSP 3.16.0 standard. - // Since this new functionality is not backwards compatible, we use a - // configuration option so the end user must opt in to it using the cli argument. - // https://github.com/microsoft/vscode/blob/1.43.0/src/vs/vscode.d.ts#L4688-L4699 + $this->doVersionedAnalysis($opened); + } - /** @psalm-suppress InvalidPropertyAssignmentValue */ - $diagnostic->code = [ - "value" => $code, - "target" => $issue_data->link, - ]; - } else { - // the Diagnostic constructor only takes `int` for the code, but the property can be - // `int` or `string`, so we set the property directly because we want to use a `string` - /** @psalm-suppress InvalidPropertyAssignmentValue */ - $diagnostic->code = $code; - } - - $diagnostics[] = $diagnostic; - } - - $this->client->textDocument->publishDiagnostics($uri, $diagnostics); + /** + * Debounced Queue File Analysis with optional version + * + * @param array $files + */ + public function doVersionedAnalysisDebounce(array $files, ?int $version = null): void + { + Loop::cancel($this->versionedAnalysisDelayToken); + if ($this->client->clientConfiguration->onChangeDebounceMs === null) { + $this->doVersionedAnalysis($files, $version); + } else { + /** @psalm-suppress MixedAssignment,UnusedPsalmSuppress */ + $this->versionedAnalysisDelayToken = Loop::delay( + $this->client->clientConfiguration->onChangeDebounceMs, + fn() => $this->doVersionedAnalysis($files, $version), + ); } } /** - * The shutdown request is sent from the client to the server. It asks the server to shut down, - * but to not exit (otherwise the response might not be delivered correctly to the client). - * There is a separate exit notification that asks the server to exit. + * Queue File Analysis with optional version * - * @psalm-suppress PossiblyUnusedReturnValue + * @param array $files + */ + public function doVersionedAnalysis(array $files, ?int $version = null): void + { + Loop::cancel($this->versionedAnalysisDelayToken); + try { + $this->logDebug("Doing Analysis from version: $version"); + $this->codebase->reloadFiles( + $this->project_analyzer, + array_keys($files), + ); + + $this->codebase->analyzer->addFilesToAnalyze( + array_combine(array_keys($files), array_keys($files)), + ); + + $this->logDebug("Reloading Files"); + $this->codebase->analyzer->analyzeFiles($this->project_analyzer, 1, false); + + $this->emitVersionedIssues($files, $version); + } catch (Throwable $e) { + $this->logError((string) $e); + } + } + + /** + * Emit Publish Diagnostics + * + * @param array $files + */ + public function emitVersionedIssues(array $files, ?int $version = null): void + { + $this->logDebug("Perform Analysis", [ + 'files' => array_keys($files), + 'version' => $version, + ]); + + //Copy variable here to be able to process it + $issue_baseline = $this->issue_baseline; + + $data = IssueBuffer::clear(); + foreach ($files as $file_path => $uri) { + //Dont report errors in files we are not watching + if (!$this->project_analyzer->getCodebase()->config->isInProjectDirs($file_path)) { + continue; + } + $diagnostics = array_map( + function (IssueData $issue_data): Diagnostic { + //$check_name = $issue->check_name; + $description = $issue_data->message; + $severity = $issue_data->severity; + + $start_line = max($issue_data->line_from, 1); + $end_line = $issue_data->line_to; + $start_column = $issue_data->column_from; + $end_column = $issue_data->column_to; + // Language server has 0 based lines and columns, phan has 1-based lines and columns. + $range = new Range( + new Position($start_line - 1, $start_column - 1), + new Position($end_line - 1, $end_column - 1), + ); + switch ($severity) { + case Config::REPORT_INFO: + $diagnostic_severity = DiagnosticSeverity::WARNING; + break; + case Config::REPORT_ERROR: + default: + $diagnostic_severity = DiagnosticSeverity::ERROR; + break; + } + $diagnostic = new Diagnostic( + $description, + $range, + null, + $diagnostic_severity, + 'psalm', + ); + + $diagnostic->data = [ + 'type' => $issue_data->type, + 'snippet' => $issue_data->snippet, + 'line_from' => $issue_data->line_from, + 'line_to' => $issue_data->line_to, + ]; + + $diagnostic->code = $issue_data->shortcode; + + /** + * Client supports a codeDescription property + * + * @since LSP 3.16.0 + */ + if ($this->clientCapabilities !== null && + $this->clientCapabilities->textDocument && + $this->clientCapabilities->textDocument->publishDiagnostics && + $this->clientCapabilities->textDocument->publishDiagnostics->codeDescriptionSupport + ) { + $diagnostic->codeDescription = new CodeDescription($issue_data->link); + } + + return $diagnostic; + }, + array_filter( + array_map(function (IssueData $issue_data) use (&$issue_baseline) { + if (empty($issue_baseline)) { + return $issue_data; + } + //Process Baseline + $file = $issue_data->file_name; + $type = $issue_data->type; + /** @psalm-suppress MixedArrayAccess */ + if (isset($issue_baseline[$file][$type]) && $issue_baseline[$file][$type]['o'] > 0) { + /** @psalm-suppress MixedArrayAccess, MixedArgument */ + if ($issue_baseline[$file][$type]['o'] === count($issue_baseline[$file][$type]['s'])) { + /** @psalm-suppress MixedArrayAccess, MixedAssignment */ + $position = array_search( + str_replace("\r\n", "\n", trim($issue_data->selected_text)), + $issue_baseline[$file][$type]['s'], + true, + ); + + if ($position !== false) { + $issue_data->severity = Config::REPORT_INFO; + /** @psalm-suppress MixedArgument */ + array_splice($issue_baseline[$file][$type]['s'], $position, 1); + /** @psalm-suppress MixedArrayAssignment, MixedOperand, MixedAssignment */ + $issue_baseline[$file][$type]['o']--; + } + } else { + /** @psalm-suppress MixedArrayAssignment */ + $issue_baseline[$file][$type]['s'] = []; + $issue_data->severity = Config::REPORT_INFO; + /** @psalm-suppress MixedArrayAssignment, MixedOperand, MixedAssignment */ + $issue_baseline[$file][$type]['o']--; + } + } + return $issue_data; + }, $data[$file_path] ?? []), + function (IssueData $issue_data) { + //Hide Warnings + if ($issue_data->severity === Config::REPORT_INFO && + $this->client->clientConfiguration->hideWarnings + ) { + return false; + } + + return true; + }, + ), + ); + + $this->client->textDocument->publishDiagnostics($uri, array_values($diagnostics), $version); + } + } + + /** + * The shutdown request is sent from the client to the server. It asks the server to shut down, but to not exit + * (otherwise the response might not be delivered correctly to the client). There is a separate exit notification + * that asks the server to exit. Clients must not send any notifications other than exit or requests to a server to + * which they have sent a shutdown request. Clients should also wait with sending the exit notification until they + * have received a response from the shutdown request. */ public function shutdown(): Promise { $this->clientStatus('closing'); - $this->verboseLog("Shutting down..."); + $this->logInfo("Shutting down..."); $codebase = $this->project_analyzer->getCodebase(); $scanned_files = $codebase->scanner->getScannedFiles(); $codebase->file_reference_provider->updateReferenceCache( @@ -441,6 +844,8 @@ class LanguageServer extends Dispatcher /** * A notification to ask the server to exit its process. + * The server should exit with success code 0 if the shutdown request has been received before; + * otherwise with error code 1. */ public function exit(): void { @@ -451,31 +856,85 @@ class LanguageServer extends Dispatcher /** * Send log message to the client * - * @param string $message The log message to send to the client. * @psalm-param 1|2|3|4 $type * @param int $type The log type: * - 1 = Error * - 2 = Warning * - 3 = Info * - 4 = Log + * @see MessageType + * @param string $message The log message to send to the client. + * @param mixed[] $context The log context */ - public function verboseLog(string $message, int $type = 4): void + public function log(int $type, string $message, array $context = []): void { - if ($this->project_analyzer->language_server_verbose) { - try { - $this->client->logMessage( - '[Psalm ' .PSALM_VERSION. ' - PHP Language Server] ' . $message, - $type, - ); - } catch (Throwable $err) { - // do nothing - } + $logLevel = $this->client->clientConfiguration->logLevel; + if ($logLevel === null) { + return; + } + + if ($type > $logLevel) { + return; + } + + if (!empty($context)) { + $message .= "\n" . json_encode($context, JSON_PRETTY_PRINT); + } + try { + $this->client->logMessage( + new LogMessage( + $type, + $message, + ), + ); + } catch (Throwable $err) { + // do nothing as we could potentially go into a loop here is not careful + //TODO: Investigate if we can use error_log instead } - new Success(null); } /** - * Send status message to client. This is the same as sending a log message, + * Log Throwable Error + */ + public function logThrowable(Throwable $throwable): void + { + $this->log(MessageType::ERROR, (string) $throwable); + } + + /** + * Log Error message to the client + */ + public function logError(string $message, array $context = []): void + { + $this->log(MessageType::ERROR, $message, $context); + } + + /** + * Log Warning message to the client + */ + public function logWarning(string $message, array $context = []): void + { + $this->log(MessageType::WARNING, $message, $context); + } + + /** + * Log Info message to the client + */ + public function logInfo(string $message, array $context = []): void + { + $this->log(MessageType::INFO, $message, $context); + } + + /** + * Log Debug message to the client + */ + public function logDebug(string $message, array $context = []): void + { + $this->log(MessageType::LOG, $message, $context); + } + + /** + * Send status message to client. This is the same as sending a log message, * except this is meant for parsing by the client to present status updates in a UI. * * @param string $status The log message to send to the client. Should not contain colons `:`. @@ -485,16 +944,15 @@ class LanguageServer extends Dispatcher private function clientStatus(string $status, ?string $additional_info = null): void { try { - // here we send a notification to the client using the telemetry notification method - $this->client->logMessage( - $status . (!empty($additional_info) ? ': ' . $additional_info : ''), - 3, - 'telemetry/event', + $this->client->event( + new LogMessage( + MessageType::INFO, + $status . (!empty($additional_info) ? ': ' . $additional_info : ''), + ), ); } catch (Throwable $err) { // do nothing } - new Success(null); } /** @@ -548,14 +1006,4 @@ class LanguageServer extends Dispatcher return $filepath; } - - /** - * Get the value of current_issues - * - * @return array> - */ - public function getCurrentIssues(): array - { - return $this->current_issues; - } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Message.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Message.php index ba1e73f9..56b46c23 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Message.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Message.php @@ -24,8 +24,6 @@ class Message /** * Parses a message - * - * @psalm-suppress UnusedMethod */ public static function parse(string $msg): Message { @@ -35,7 +33,9 @@ class Message foreach ($parts as $line) { if ($line) { $pair = explode(': ', $line); - $obj->headers[$pair[0]] = $pair[1]; + if (isset($pair[1])) { + $obj->headers[$pair[0]] = $pair[1]; + } } } @@ -56,6 +56,7 @@ class Message public function __toString(): string { + $body = (string)$this->body; $contentLength = strlen($body); $this->headers['Content-Length'] = (string) $contentLength; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/PHPMarkdownContent.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/PHPMarkdownContent.php new file mode 100644 index 00000000..3290ea5c --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/PHPMarkdownContent.php @@ -0,0 +1,58 @@ +code = $code; + $this->title = $title; + $this->description = $description; + + $markdown = ''; + if ($title !== null) { + $markdown = "**$title**\n\n"; + } + if ($description !== null) { + $markdown = "$markdown$description\n\n"; + } + parent::__construct( + MarkupKind::MARKDOWN, + "$markdown```php\nserver = $server; + } + + public function debug(string $message): void + { + if ($this->server) { + $this->server->logDebug(str_replace("\n", "", $message)); + } + } + + public function write(string $message): void + { + if ($this->server) { + $this->server->logInfo(str_replace("\n", "", $message)); + } + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php index 66ef9af9..35031d85 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php @@ -91,7 +91,9 @@ class ProtocolStreamReader implements ProtocolReader $this->buffer = ''; } elseif (substr($this->buffer, -2) === "\r\n") { $parts = explode(':', $this->buffer); - $this->headers[$parts[0]] = trim($parts[1]); + if (isset($parts[1])) { + $this->headers[$parts[0]] = trim($parts[1]); + } $this->buffer = ''; } break; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ClassLikeStorageCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ClassLikeStorageCacheProvider.php new file mode 100644 index 00000000..f1925fe7 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ClassLikeStorageCacheProvider.php @@ -0,0 +1,47 @@ + */ + private array $cache = []; + + public function __construct() + { + } + + public function writeToCache(ClassLikeStorage $storage, ?string $file_path, ?string $file_contents): void + { + $fq_classlike_name_lc = strtolower($storage->name); + $this->cache[$fq_classlike_name_lc] = $storage; + } + + public function getLatestFromCache( + string $fq_classlike_name_lc, + ?string $file_path, + ?string $file_contents + ): ClassLikeStorage { + $cached_value = $this->loadFromCache($fq_classlike_name_lc); + + if (!$cached_value) { + throw new UnexpectedValueException('Should be in cache'); + } + + return $cached_value; + } + + private function loadFromCache(string $fq_classlike_name_lc): ?ClassLikeStorage + { + return $this->cache[$fq_classlike_name_lc] ?? null; + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.php new file mode 100644 index 00000000..79d54534 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.php @@ -0,0 +1,280 @@ +> */ + private array $cached_correct_methods = []; + + /** + * @var array< + * string, + * array{ + * 0: array, + * 1: array, + * 2: array + * } + * > + */ + private array $cached_file_maps = []; + + public function __construct(Config $config) + { + $this->config = $config; + } + + public function getCachedFileReferences(): ?array + { + return $this->cached_file_references; + } + + public function getCachedClassLikeFiles(): ?array + { + return $this->cached_classlike_files; + } + + public function getCachedMethodClassReferences(): ?array + { + return $this->cached_method_class_references; + } + + public function getCachedNonMethodClassReferences(): ?array + { + return $this->cached_nonmethod_class_references; + } + + public function getCachedFileMemberReferences(): ?array + { + return $this->cached_file_member_references; + } + + public function getCachedFilePropertyReferences(): ?array + { + return $this->cached_file_property_references; + } + + public function getCachedFileMethodReturnReferences(): ?array + { + return $this->cached_file_method_return_references; + } + + public function getCachedMethodMemberReferences(): ?array + { + return $this->cached_method_member_references; + } + + public function getCachedMethodDependencies(): ?array + { + return $this->cached_method_dependencies; + } + + public function getCachedMethodPropertyReferences(): ?array + { + return $this->cached_method_property_references; + } + + public function getCachedMethodMethodReturnReferences(): ?array + { + return $this->cached_method_method_return_references; + } + + public function getCachedFileMissingMemberReferences(): ?array + { + return $this->cached_file_missing_member_references; + } + + public function getCachedMixedMemberNameReferences(): ?array + { + return $this->cached_unknown_member_references; + } + + public function getCachedMethodMissingMemberReferences(): ?array + { + return $this->cached_method_missing_member_references; + } + + public function getCachedMethodParamUses(): ?array + { + return $this->cached_method_param_uses; + } + + public function getCachedIssues(): ?array + { + return $this->cached_issues; + } + + public function setCachedFileReferences(array $file_references): void + { + $this->cached_file_references = $file_references; + } + + public function setCachedClassLikeFiles(array $file_references): void + { + $this->cached_classlike_files = $file_references; + } + + public function setCachedMethodClassReferences(array $method_class_references): void + { + $this->cached_method_class_references = $method_class_references; + } + + public function setCachedNonMethodClassReferences(array $file_class_references): void + { + $this->cached_nonmethod_class_references = $file_class_references; + } + + public function setCachedMethodMemberReferences(array $member_references): void + { + $this->cached_method_member_references = $member_references; + } + + public function setCachedMethodDependencies(array $member_references): void + { + $this->cached_method_dependencies = $member_references; + } + + public function setCachedMethodPropertyReferences(array $property_references): void + { + $this->cached_method_property_references = $property_references; + } + + public function setCachedMethodMethodReturnReferences(array $method_return_references): void + { + $this->cached_method_method_return_references = $method_return_references; + } + + public function setCachedMethodMissingMemberReferences(array $member_references): void + { + $this->cached_method_missing_member_references = $member_references; + } + + public function setCachedFileMemberReferences(array $member_references): void + { + $this->cached_file_member_references = $member_references; + } + + public function setCachedFilePropertyReferences(array $property_references): void + { + $this->cached_file_property_references = $property_references; + } + + public function setCachedFileMethodReturnReferences(array $method_return_references): void + { + $this->cached_file_method_return_references = $method_return_references; + } + + public function setCachedFileMissingMemberReferences(array $member_references): void + { + $this->cached_file_missing_member_references = $member_references; + } + + public function setCachedMixedMemberNameReferences(array $references): void + { + $this->cached_unknown_member_references = $references; + } + + public function setCachedMethodParamUses(array $uses): void + { + $this->cached_method_param_uses = $uses; + } + + public function setCachedIssues(array $issues): void + { + $this->cached_issues = $issues; + } + + /** + * @return array> + */ + public function getAnalyzedMethodCache(): array + { + return $this->cached_correct_methods; + } + + /** + * @param array> $analyzed_methods + */ + public function setAnalyzedMethodCache(array $analyzed_methods): void + { + $this->cached_correct_methods = $analyzed_methods; + } + + /** + * @return array< + * string, + * array{ + * 0: array, + * 1: array, + * 2: array + * } + * > + */ + public function getFileMapCache(): array + { + return $this->cached_file_maps; + } + + /** + * @param array< + * string, + * array{ + * 0: array, + * 1: array, + * 2: array + * } + * > $file_maps + */ + public function setFileMapCache(array $file_maps): void + { + $this->cached_file_maps = $file_maps; + } + + /** + * @param array $mixed_counts + */ + public function setTypeCoverage(array $mixed_counts): void + { + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.php new file mode 100644 index 00000000..c91ffcc1 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.php @@ -0,0 +1,48 @@ + */ + private array $cache = []; + + public function __construct() + { + } + + public function writeToCache(FileStorage $storage, string $file_contents): void + { + $file_path = strtolower($storage->file_path); + $this->cache[$file_path] = $storage; + } + + public function getLatestFromCache(string $file_path, string $file_contents): ?FileStorage + { + $cached_value = $this->loadFromCache(strtolower($file_path)); + + if (!$cached_value) { + return null; + } + + return $cached_value; + } + + public function removeCacheForFile(string $file_path): void + { + unset($this->cache[strtolower($file_path)]); + } + + private function loadFromCache(string $file_path): ?FileStorage + { + return $this->cache[strtolower($file_path)] ?? null; + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ParserCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ParserCacheProvider.php new file mode 100644 index 00000000..0b30a2dd --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ParserCacheProvider.php @@ -0,0 +1,109 @@ + + */ + private array $file_contents_cache = []; + + /** + * @var array + */ + private array $file_content_hash = []; + + /** + * @var array> + */ + private array $statements_cache = []; + + /** + * @var array + */ + private array $statements_cache_time = []; + + public function __construct() + { + } + + public function loadStatementsFromCache( + string $file_path, + int $file_modified_time, + string $file_content_hash + ): ?array { + if (isset($this->statements_cache[$file_path]) + && $this->statements_cache_time[$file_path] >= $file_modified_time + && $this->file_content_hash[$file_path] === $file_content_hash + ) { + return $this->statements_cache[$file_path]; + } + + return null; + } + + /** + * @return list|null + */ + public function loadExistingStatementsFromCache(string $file_path): ?array + { + if (isset($this->statements_cache[$file_path])) { + return $this->statements_cache[$file_path]; + } + + return null; + } + + /** + * @param list $stmts + */ + public function saveStatementsToCache( + string $file_path, + string $file_content_hash, + array $stmts, + bool $touch_only + ): void { + $this->statements_cache[$file_path] = $stmts; + $this->statements_cache_time[$file_path] = microtime(true); + $this->file_content_hash[$file_path] = $file_content_hash; + } + + public function loadExistingFileContentsFromCache(string $file_path): ?string + { + if (isset($this->file_contents_cache[$file_path])) { + return $this->file_contents_cache[$file_path]; + } + + return null; + } + + public function cacheFileContents(string $file_path, string $file_contents): void + { + $this->file_contents_cache[$file_path] = $file_contents; + } + + public function deleteOldParserCaches(float $time_before): int + { + $this->existing_file_content_hashes = null; + $this->new_file_content_hashes = []; + + $this->file_contents_cache = []; + $this->file_content_hash = []; + $this->statements_cache = []; + $this->statements_cache_time = []; + return 0; + } + + public function saveFileContentHashes(): void + { + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ProjectCacheProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ProjectCacheProvider.php new file mode 100644 index 00000000..ed210fa0 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Provider/ProjectCacheProvider.php @@ -0,0 +1,41 @@ +last_run; + } + + public function processSuccessfulRun(float $start_time, string $psalm_version): void + { + $this->last_run = (int) $start_time; + } + + public function canDiffFiles(): bool + { + return $this->last_run > 0; + } + + public function hasLockfileChanged(): bool + { + return false; + } + + public function updateComposerLockHash(): void + { + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Reference.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Reference.php new file mode 100644 index 00000000..32694c7c --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Reference.php @@ -0,0 +1,22 @@ +file_path = $file_path; + $this->symbol = $symbol; + $this->range = $range; + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/TextDocument.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/TextDocument.php index 87d4c650..b9c4bcca 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/TextDocument.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/TextDocument.php @@ -6,11 +6,12 @@ namespace Psalm\Internal\LanguageServer\Server; use Amp\Promise; use Amp\Success; +use LanguageServerProtocol\CodeAction; +use LanguageServerProtocol\CodeActionContext; +use LanguageServerProtocol\CodeActionKind; use LanguageServerProtocol\CompletionList; use LanguageServerProtocol\Hover; use LanguageServerProtocol\Location; -use LanguageServerProtocol\MarkupContent; -use LanguageServerProtocol\MarkupKind; use LanguageServerProtocol\Position; use LanguageServerProtocol\Range; use LanguageServerProtocol\SignatureHelp; @@ -21,6 +22,7 @@ use LanguageServerProtocol\TextEdit; use LanguageServerProtocol\VersionedTextDocumentIdentifier; use LanguageServerProtocol\WorkspaceEdit; use Psalm\Codebase; +use Psalm\Exception\TypeParseTreeException; use Psalm\Exception\UnanalyzedFileException; use Psalm\Internal\Analyzer\ProjectAnalyzer; use Psalm\Internal\LanguageServer\LanguageServer; @@ -28,7 +30,6 @@ use UnexpectedValueException; use function array_values; use function count; -use function error_log; use function preg_match; use function substr_count; @@ -68,36 +69,41 @@ class TextDocument */ public function didOpen(TextDocumentItem $textDocument): void { + $this->server->logDebug( + 'textDocument/didOpen', + ['version' => $textDocument->version, 'uri' => $textDocument->uri], + ); + $file_path = LanguageServer::uriToPath($textDocument->uri); - if (!$this->codebase->config->isInProjectDirs($file_path)) { - return; - } - + $this->codebase->removeTemporaryFileChanges($file_path); $this->codebase->file_provider->openFile($file_path); + $this->codebase->file_provider->setOpenContents($file_path, $textDocument->text); - $this->server->queueFileAnalysis($file_path, $textDocument->uri); + $this->server->queueOpenFileAnalysis($file_path, $textDocument->uri, $textDocument->version); } /** * The document save notification is sent from the client to the server when the document was saved in the client * - * @param TextDocumentItem $textDocument the document that was opened - * @param ?string $text the content when saved + * @param TextDocumentIdentifier $textDocument the document that was opened + * @param string|null $text Optional the content when saved. Depends on the includeText value + * when the save notification was requested. */ - public function didSave(TextDocumentItem $textDocument, ?string $text): void + public function didSave(TextDocumentIdentifier $textDocument, ?string $text = null): void { - $file_path = LanguageServer::uriToPath($textDocument->uri); + $this->server->logDebug( + 'textDocument/didSave', + ['uri' => (array) $textDocument], + ); - if (!$this->codebase->config->isInProjectDirs($file_path)) { - return; - } + $file_path = LanguageServer::uriToPath($textDocument->uri); // reopen file $this->codebase->removeTemporaryFileChanges($file_path); - $this->codebase->file_provider->setOpenContents($file_path, (string) $text); + $this->codebase->file_provider->setOpenContents($file_path, $text); - $this->server->queueFileAnalysis($file_path, $textDocument->uri); + $this->server->queueSaveFileAnalysis($file_path, $textDocument->uri); } /** @@ -108,13 +114,14 @@ class TextDocument */ public function didChange(VersionedTextDocumentIdentifier $textDocument, array $contentChanges): void { + $this->server->logDebug( + 'textDocument/didChange', + ['version' => $textDocument->version, 'uri' => $textDocument->uri], + ); + $file_path = LanguageServer::uriToPath($textDocument->uri); - if (!$this->codebase->config->isInProjectDirs($file_path)) { - return; - } - - if (count($contentChanges) === 1 && $contentChanges[0]->range === null) { + if (count($contentChanges) === 1 && isset($contentChanges[0]) && $contentChanges[0]->range === null) { $new_content = $contentChanges[0]->text; } else { throw new UnexpectedValueException('Not expecting partial diff'); @@ -126,8 +133,8 @@ class TextDocument } } - $this->codebase->addTemporaryFileChanges($file_path, $new_content); - $this->server->queueTemporaryFileAnalysis($file_path, $textDocument->uri); + $this->codebase->addTemporaryFileChanges($file_path, $new_content, $textDocument->version); + $this->server->queueChangeFileAnalysis($file_path, $textDocument->uri, $textDocument->version); } /** @@ -142,6 +149,11 @@ class TextDocument */ public function didClose(TextDocumentIdentifier $textDocument): void { + $this->server->logDebug( + 'textDocument/didClose', + ['uri' => $textDocument->uri], + ); + $file_path = LanguageServer::uriToPath($textDocument->uri); $this->codebase->file_provider->closeFile($file_path); @@ -158,24 +170,34 @@ class TextDocument */ public function definition(TextDocumentIdentifier $textDocument, Position $position): Promise { + if (!$this->server->client->clientConfiguration->provideDefinition) { + return new Success(null); + } + + $this->server->logDebug( + 'textDocument/definition', + ); + $file_path = LanguageServer::uriToPath($textDocument->uri); + //This currently doesnt work right with out of project files + if (!$this->codebase->config->isInProjectDirs($file_path)) { + return new Success(null); + } + try { - $reference_location = $this->codebase->getReferenceAtPosition($file_path, $position); + $reference = $this->codebase->getReferenceAtPositionAsReference($file_path, $position); } catch (UnanalyzedFileException $e) { - $this->codebase->file_provider->openFile($file_path); - $this->server->queueFileAnalysis($file_path, $textDocument->uri); - + $this->server->logThrowable($e); return new Success(null); } - if ($reference_location === null) { + if ($reference === null) { return new Success(null); } - [$reference] = $reference_location; - $code_location = $this->codebase->getSymbolLocation($file_path, $reference); + $code_location = $this->codebase->getSymbolLocationByReference($reference); if (!$code_location) { return new Success(null); @@ -202,39 +224,44 @@ class TextDocument */ public function hover(TextDocumentIdentifier $textDocument, Position $position): Promise { - $file_path = LanguageServer::uriToPath($textDocument->uri); - - try { - $reference_location = $this->codebase->getReferenceAtPosition($file_path, $position); - } catch (UnanalyzedFileException $e) { - $this->codebase->file_provider->openFile($file_path); - $this->server->queueFileAnalysis($file_path, $textDocument->uri); - + if (!$this->server->client->clientConfiguration->provideHover) { return new Success(null); } - if ($reference_location === null) { - return new Success(null); - } - - [$reference, $range] = $reference_location; - - $symbol_information = $this->codebase->getSymbolInformation($file_path, $reference); - - if ($symbol_information === null) { - return new Success(null); - } - - $content = "```php\n" . $symbol_information['type'] . "\n```"; - if (isset($symbol_information['description'])) { - $content .= "\n---\n" . $symbol_information['description']; - } - $contents = new MarkupContent( - MarkupKind::MARKDOWN, - $content, + $this->server->logDebug( + 'textDocument/hover', ); - return new Success(new Hover($contents, $range)); + $file_path = LanguageServer::uriToPath($textDocument->uri); + + //This currently doesnt work right with out of project files + if (!$this->codebase->config->isInProjectDirs($file_path)) { + return new Success(null); + } + + try { + $reference = $this->codebase->getReferenceAtPositionAsReference($file_path, $position); + } catch (UnanalyzedFileException $e) { + $this->server->logThrowable($e); + return new Success(null); + } + + if ($reference === null) { + return new Success(null); + } + + try { + $markup = $this->codebase->getMarkupContentForSymbolByReference($reference); + } catch (UnexpectedValueException $e) { + $this->server->logThrowable($e); + return new Success(null); + } + + if ($markup === null) { + return new Success(null); + } + + return new Success(new Hover($markup, $reference->range)); } /** @@ -249,56 +276,74 @@ class TextDocument * * @param TextDocumentIdentifier $textDocument The text document * @param Position $position The position - * @psalm-return Promise>|Promise + * @psalm-return Promise>|Promise|Promise */ public function completion(TextDocumentIdentifier $textDocument, Position $position): Promise { + if (!$this->server->client->clientConfiguration->provideCompletion) { + return new Success(null); + } + + $this->server->logDebug( + 'textDocument/completion', + ); + $file_path = LanguageServer::uriToPath($textDocument->uri); + + //This currently doesnt work right with out of project files if (!$this->codebase->config->isInProjectDirs($file_path)) { - return new Success([]); + return new Success(null); } try { $completion_data = $this->codebase->getCompletionDataAtPosition($file_path, $position); - } catch (UnanalyzedFileException $e) { - $this->codebase->file_provider->openFile($file_path); - $this->server->queueFileAnalysis($file_path, $textDocument->uri); + if ($completion_data) { + [$recent_type, $gap, $offset] = $completion_data; - return new Success([]); + if ($gap === '->' || $gap === '::') { + $snippetSupport = ($this->server->clientCapabilities && + $this->server->clientCapabilities->textDocument && + $this->server->clientCapabilities->textDocument->completion && + $this->server->clientCapabilities->textDocument->completion->completionItem && + $this->server->clientCapabilities->textDocument->completion->completionItem->snippetSupport) + ? true : false; + $completion_items = + $this->codebase->getCompletionItemsForClassishThing($recent_type, $gap, $snippetSupport); + } elseif ($gap === '[') { + $completion_items = $this->codebase->getCompletionItemsForArrayKeys($recent_type); + } else { + $completion_items = $this->codebase->getCompletionItemsForPartialSymbol( + $recent_type, + $offset, + $file_path, + ); + } + return new Success(new CompletionList($completion_items, false)); + } + } catch (UnanalyzedFileException $e) { + $this->server->logThrowable($e); + return new Success(null); + } catch (TypeParseTreeException $e) { + $this->server->logThrowable($e); + return new Success(null); } try { $type_context = $this->codebase->getTypeContextAtPosition($file_path, $position); - } catch (UnexpectedValueException $e) { - error_log('completion errored at ' . $position->line . ':' . $position->character. - ', Reason: '.$e->getMessage()); - return new Success([]); - } - - if (!$completion_data && !$type_context) { - error_log('completion not found at ' . $position->line . ':' . $position->character); - return new Success([]); - } - - if ($completion_data) { - [$recent_type, $gap, $offset] = $completion_data; - - if ($gap === '->' || $gap === '::') { - $completion_items = $this->codebase->getCompletionItemsForClassishThing($recent_type, $gap); - } elseif ($gap === '[') { - $completion_items = $this->codebase->getCompletionItemsForArrayKeys($recent_type); - } else { - $completion_items = $this->codebase->getCompletionItemsForPartialSymbol( - $recent_type, - $offset, - $file_path, - ); + if ($type_context) { + $completion_items = $this->codebase->getCompletionItemsForType($type_context); + return new Success(new CompletionList($completion_items, false)); } - } else { - $completion_items = $this->codebase->getCompletionItemsForType($type_context); + } catch (UnexpectedValueException $e) { + $this->server->logThrowable($e); + return new Success(null); + } catch (TypeParseTreeException $e) { + $this->server->logThrowable($e); + return new Success(null); } - return new Success(new CompletionList($completion_items, false)); + $this->server->logError('completion not found at ' . $position->line . ':' . $position->character); + return new Success(null); } /** @@ -307,96 +352,134 @@ class TextDocument */ public function signatureHelp(TextDocumentIdentifier $textDocument, Position $position): Promise { + if (!$this->server->client->clientConfiguration->provideSignatureHelp) { + return new Success(null); + } + + $this->server->logDebug( + 'textDocument/signatureHelp', + ); + $file_path = LanguageServer::uriToPath($textDocument->uri); + //This currently doesnt work right with out of project files + if (!$this->codebase->config->isInProjectDirs($file_path)) { + return new Success(null); + } + try { $argument_location = $this->codebase->getFunctionArgumentAtPosition($file_path, $position); } catch (UnanalyzedFileException $e) { - $this->codebase->file_provider->openFile($file_path); - $this->server->queueFileAnalysis($file_path, $textDocument->uri); - - return new Success(new SignatureHelp()); + $this->server->logThrowable($e); + return new Success(null); } if ($argument_location === null) { - return new Success(new SignatureHelp()); + return new Success(null); } - $signature_information = $this->codebase->getSignatureInformation($argument_location[0], $file_path); + try { + $signature_information = $this->codebase->getSignatureInformation($argument_location[0], $file_path); + } catch (UnexpectedValueException $e) { + $this->server->logThrowable($e); + return new Success(null); + } if (!$signature_information) { - return new Success(new SignatureHelp()); + return new Success(null); } - return new Success(new SignatureHelp([ - $signature_information, - ], 0, $argument_location[1])); + return new Success( + new SignatureHelp( + [$signature_information], + 0, + $argument_location[1], + ), + ); } /** * The code action request is sent from the client to the server to compute commands * for a given text document and range. These commands are typically code fixes to * either fix problems or to beautify/refactor code. + * + * @psalm-suppress PossiblyUnusedParam */ - public function codeAction(TextDocumentIdentifier $textDocument, Range $range): Promise + public function codeAction(TextDocumentIdentifier $textDocument, Range $range, CodeActionContext $context): Promise { + if (!$this->server->client->clientConfiguration->provideCodeActions) { + return new Success(null); + } + + $this->server->logDebug( + 'textDocument/codeAction', + ); + $file_path = LanguageServer::uriToPath($textDocument->uri); - if (!$this->codebase->file_provider->isOpen($file_path)) { + + //Don't report code actions for files we arent watching + if (!$this->codebase->config->isInProjectDirs($file_path)) { return new Success(null); } - $issues = $this->server->getCurrentIssues(); - - if (empty($issues[$file_path])) { - return new Success(null); - } - - $file_contents = $this->codebase->getFileContents($file_path); - - $offsetStart = $range->start->toOffset($file_contents); - $offsetEnd = $range->end->toOffset($file_contents); - $fixers = []; - foreach ($issues[$file_path] as $issue) { - if ($offsetStart === $issue->from && $offsetEnd === $issue->to) { - $snippetRange = new Range( - new Position($issue->line_from-1), - new Position($issue->line_to), - ); + foreach ($context->diagnostics as $diagnostic) { + if ($diagnostic->source !== 'psalm') { + continue; + } - $indentation = ''; - if (preg_match('/^(\s*)/', $issue->snippet, $matches)) { - $indentation = $matches[1] ?? ''; - } + /** @var array{type: string, snippet: string, line_from: int, line_to: int} */ + $data = (array)$diagnostic->data; - /** - * Suppress Psalm because ther are bugs in how - * LanguageServer's signature of WorkspaceEdit is declared: - * - * See: - * https://github.com/felixfbecker/php-language-server-protocol - * See: - * https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#workspaceEdit - */ - $edit = new WorkspaceEdit([ + //$file_path = LanguageServer::uriToPath($textDocument->uri); + //$contents = $this->codebase->file_provider->getContents($file_path); + + $snippetRange = new Range( + new Position($data['line_from']-1), + new Position($data['line_to']), + ); + + $indentation = ''; + if (preg_match('/^(\s*)/', $data['snippet'], $matches)) { + $indentation = $matches[1] ?? ''; + } + + //Suppress Ability + $fixers["suppress.{$data['type']}"] = new CodeAction( + "Suppress {$data['type']} for this line", + CodeActionKind::QUICK_FIX, + null, + null, + null, + new WorkspaceEdit([ $textDocument->uri => [ new TextEdit( $snippetRange, - "{$indentation}/**\n". - "{$indentation} * @psalm-suppress {$issue->type}\n". - "{$indentation} */\n". - "{$issue->snippet}\n", + "{$indentation}/** @psalm-suppress {$data['type']} */\n". + "{$data['snippet']}\n", ), ], - ]); + ]), + ); - //Suppress Ability - $fixers["suppress.{$issue->type}"] = [ - 'title' => "Suppress {$issue->type} for this line", - 'kind' => 'quickfix', - 'edit' => $edit, - ]; - } + /* + $fixers["fixAll.{$diagnostic->data->type}"] = new CodeAction( + "FixAll {$diagnostic->data->type} for this file", + CodeActionKind::QUICK_FIX, + null, + null, + null, + null, + new Command( + "Fix All", + "psalm.fixall", + [ + 'uri' => $textDocument->uri, + 'type' => $diagnostic->data->type + ] + ) + ); + */ } if (empty($fixers)) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/Workspace.php b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/Workspace.php index 333c1bb6..af49619c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/Workspace.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/LanguageServer/Server/Workspace.php @@ -4,11 +4,21 @@ declare(strict_types=1); namespace Psalm\Internal\LanguageServer\Server; +use Amp\Promise; +use Amp\Success; +use InvalidArgumentException; use LanguageServerProtocol\FileChangeType; use LanguageServerProtocol\FileEvent; use Psalm\Codebase; use Psalm\Internal\Analyzer\ProjectAnalyzer; +use Psalm\Internal\Composer; use Psalm\Internal\LanguageServer\LanguageServer; +use Psalm\Internal\Provider\FileReferenceProvider; + +use function array_filter; +use function array_map; +use function in_array; +use function realpath; /** * Provides method handlers for all workspace/* methods @@ -46,9 +56,35 @@ class Workspace */ public function didChangeWatchedFiles(array $changes): void { + $this->server->logDebug( + 'workspace/didChangeWatchedFiles', + ); + + $realFiles = array_filter( + array_map(function (FileEvent $change) { + try { + return LanguageServer::uriToPath($change->uri); + } catch (InvalidArgumentException $e) { + return null; + } + }, $changes), + ); + + $composerLockFile = realpath(Composer::getLockFilePath($this->codebase->config->base_dir)); + if (in_array($composerLockFile, $realFiles)) { + $this->server->logInfo('Composer.lock file changed. Reloading codebase'); + FileReferenceProvider::clearCache(); + $this->server->queueFileAnalysisWithOpenedFiles(); + return; + } + foreach ($changes as $change) { $file_path = LanguageServer::uriToPath($change->uri); + if ($composerLockFile === $file_path) { + continue; + } + if ($change->type === FileChangeType::DELETED) { $this->codebase->invalidateInformationForFile($file_path); continue; @@ -62,10 +98,64 @@ class Workspace continue; } - //If the file is currently open then dont analyse it because its tracked by the client + //If the file is currently open then dont analize it because its tracked in didChange if (!$this->codebase->file_provider->isOpen($file_path)) { - $this->server->queueFileAnalysis($file_path, $change->uri); + $this->server->queueClosedFileAnalysis($file_path, $change->uri); } } } + + /** + * A notification sent from the client to the server to signal the change of configuration settings. + * + * @param mixed $settings + * @psalm-suppress PossiblyUnusedMethod, PossiblyUnusedParam + */ + public function didChangeConfiguration($settings): void + { + $this->server->logDebug( + 'workspace/didChangeConfiguration', + ); + $this->server->client->refreshConfiguration(); + } + + /** + * The workspace/executeCommand request is sent from the client to the server to + * trigger command execution on the server. + * + * @param mixed $arguments + * @psalm-suppress PossiblyUnusedMethod + */ + public function executeCommand(string $command, $arguments): Promise + { + $this->server->logDebug( + 'workspace/executeCommand', + [ + 'command' => $command, + 'arguments' => $arguments, + ], + ); + + switch ($command) { + case 'psalm.analyze.uri': + /** @var array{uri: string} */ + $arguments = (array) $arguments; + $file = LanguageServer::uriToPath($arguments['uri']); + $this->codebase->reloadFiles( + $this->project_analyzer, + [$file], + true, + ); + + $this->codebase->analyzer->addFilesToAnalyze( + [$file => $file], + ); + $this->codebase->analyzer->analyzeFiles($this->project_analyzer, 1, false); + + $this->server->emitVersionedIssues([$file => $arguments['uri']]); + break; + } + + return new Success(null); + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php index 38f524b6..2f1c5467 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php @@ -241,10 +241,24 @@ class ClassLikeDocblockParser if (isset($parsed_docblock->tags['psalm-seal-properties'])) { $info->sealed_properties = true; } + if (isset($parsed_docblock->tags['psalm-no-seal-properties'])) { + $info->sealed_properties = false; + } if (isset($parsed_docblock->tags['psalm-seal-methods'])) { $info->sealed_methods = true; } + if (isset($parsed_docblock->tags['psalm-no-seal-methods'])) { + $info->sealed_methods = false; + } + + if (isset($parsed_docblock->tags['psalm-inheritors'])) { + foreach ($parsed_docblock->tags['psalm-inheritors'] as $template_line) { + $doc_line_parts = CommentAnalyzer::splitDocLine($template_line); + $doc_line_parts[0] = CommentAnalyzer::sanitizeDocblockType($doc_line_parts[0]); + $info->inheritors = $doc_line_parts[0]; + } + } if (isset($parsed_docblock->tags['psalm-immutable']) || isset($parsed_docblock->tags['psalm-mutation-free']) @@ -296,6 +310,9 @@ class ClassLikeDocblockParser } if (isset($parsed_docblock->combined_tags['method'])) { + if ($info->sealed_methods === null) { + $info->sealed_methods = true; + } foreach ($parsed_docblock->combined_tags['method'] as $offset => $method_entry) { $method_entry = preg_replace('/[ \t]+/', ' ', trim($method_entry)); @@ -481,6 +498,13 @@ class ClassLikeDocblockParser $info->public_api = isset($parsed_docblock->tags['psalm-api']) || isset($parsed_docblock->tags['api']); + if (isset($parsed_docblock->tags['property']) + && $codebase->config->docblock_property_types_seal_properties + && $info->sealed_properties === null + ) { + $info->sealed_properties = true; + } + self::addMagicPropertyToInfo($comment, $info, $parsed_docblock->tags, 'property'); self::addMagicPropertyToInfo($comment, $info, $parsed_docblock->tags, 'psalm-property'); self::addMagicPropertyToInfo($comment, $info, $parsed_docblock->tags, 'property-read'); diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php index 6331b7ec..2bc9d718 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php @@ -143,6 +143,7 @@ class ClassLikeNodeScanner /** * @return false|null + * @psalm-suppress ComplexMethod */ public function start(PhpParser\Node\Stmt\ClassLike $node): ?bool { @@ -420,10 +421,19 @@ class ClassLikeNodeScanner if ($template_map[1] !== null && $template_map[2] !== null) { if (trim($template_map[2])) { + $type_string = $template_map[2]; + try { + $type_string = CommentAnalyzer::splitDocLine($type_string)[0]; + } catch (DocblockParseException $e) { + throw new DocblockParseException( + $type_string . ' is not a valid type: ' . $e->getMessage(), + ); + } + $type_string = CommentAnalyzer::sanitizeDocblockType($type_string); try { $template_type = TypeParser::parseTokens( TypeTokenizer::getFullyQualifiedTokens( - $template_map[2], + $type_string, $this->aliases, $storage->template_types, $this->type_aliases, @@ -529,6 +539,31 @@ class ClassLikeNodeScanner $storage->sealed_properties = $docblock_info->sealed_properties; $storage->sealed_methods = $docblock_info->sealed_methods; + + if ($docblock_info->inheritors) { + try { + $storage->inheritors = TypeParser::parseTokens( + TypeTokenizer::getFullyQualifiedTokens( + $docblock_info->inheritors, + $storage->aliases, + $storage->template_types ?? [], + $storage->type_aliases, + $fq_classlike_name, + ), + null, + $storage->template_types ?? [], + $storage->type_aliases, + true, + ); + } catch (TypeParseTreeException $e) { + $storage->docblock_issues[] = new InvalidDocblock( + '@psalm-inheritors contains invalid reference:' . $e->getMessage(), + $name_location ?? $class_location, + ); + } + } + + if ($docblock_info->properties) { foreach ($docblock_info->properties as $property) { $pseudo_property_type_tokens = TypeTokenizer::getFullyQualifiedTokens( @@ -567,8 +602,6 @@ class ClassLikeNodeScanner ); } } - - $storage->sealed_properties = true; } foreach ($docblock_info->methods as $method) { @@ -595,8 +628,6 @@ class ClassLikeNodeScanner $lc_method_name, ); } - - $storage->sealed_methods = true; } @@ -1173,7 +1204,7 @@ class ClassLikeNodeScanner $storage->template_type_uses_count[$generic_class_lc] = count($atomic_type->type_params); foreach ($atomic_type->type_params as $type_param) { - $used_type_parameters[] = $type_param; + $used_type_parameters[] = $type_param->replaceClassLike('self', $storage->name); } $storage->template_extended_offsets[$atomic_type->value] = $used_type_parameters; @@ -1905,9 +1936,12 @@ class ClassLikeNodeScanner } $type_string = str_replace("\n", '', implode('', $var_line_parts)); - - // Strip any remaining characters after the last grouping character >, } or ) - $type_string = preg_replace('/(?<=[>})])[^>})]*$/', '', $type_string, 1); + try { + $type_string = CommentAnalyzer::splitDocLine($type_string)[0]; + } catch (DocblockParseException $e) { + throw new DocblockParseException($type_string . ' is not a valid type: '.$e->getMessage()); + } + $type_string = CommentAnalyzer::sanitizeDocblockType($type_string); try { $type_tokens = TypeTokenizer::getFullyQualifiedTokens( diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php index 021b8930..20c75007 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php @@ -15,6 +15,8 @@ use Psalm\Internal\Scanner\UnresolvedConstant\ArraySpread; use Psalm\Internal\Scanner\UnresolvedConstant\ArrayValue; use Psalm\Internal\Scanner\UnresolvedConstant\ClassConstant; use Psalm\Internal\Scanner\UnresolvedConstant\Constant; +use Psalm\Internal\Scanner\UnresolvedConstant\EnumNameFetch; +use Psalm\Internal\Scanner\UnresolvedConstant\EnumValueFetch; use Psalm\Internal\Scanner\UnresolvedConstant\KeyValuePair; use Psalm\Internal\Scanner\UnresolvedConstant\ScalarValue; use Psalm\Internal\Scanner\UnresolvedConstant\UnresolvedAdditionOp; @@ -34,6 +36,7 @@ use function assert; use function class_exists; use function function_exists; use function implode; +use function in_array; use function interface_exists; use function strtolower; @@ -297,6 +300,24 @@ class ExpressionResolver return new ArrayValue($items); } + if ($stmt instanceof PhpParser\Node\Expr\PropertyFetch + && $stmt->var instanceof PhpParser\Node\Expr\ClassConstFetch + && $stmt->var->class instanceof PhpParser\Node\Name + && $stmt->var->name instanceof PhpParser\Node\Identifier + && $stmt->name instanceof PhpParser\Node\Identifier + && in_array($stmt->name->name, ['name', 'value', true]) + ) { + $enum_fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject( + $stmt->var->class, + $aliases, + ); + if ($stmt->name->name === 'value') { + return new EnumValueFetch($enum_fq_class_name, $stmt->var->name->name); + } elseif ($stmt->name->name === 'name') { + return new EnumNameFetch($enum_fq_class_name, $stmt->var->name->name); + } + } + return null; } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php index f0cc1dc5..9f9a477c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php @@ -9,8 +9,10 @@ use Psalm\CodeLocation; use Psalm\CodeLocation\DocblockTypeLocation; use Psalm\Codebase; use Psalm\Config; +use Psalm\Exception\DocblockParseException; use Psalm\Exception\InvalidMethodOverrideException; use Psalm\Exception\TypeParseTreeException; +use Psalm\Internal\Analyzer\CommentAnalyzer; use Psalm\Internal\Analyzer\NamespaceAnalyzer; use Psalm\Internal\Scanner\FileScanner; use Psalm\Internal\Scanner\FunctionDocblockComment; @@ -61,6 +63,7 @@ use function strlen; use function strpos; use function strtolower; use function substr; +use function substr_replace; use function trim; /** @@ -1252,7 +1255,7 @@ class FunctionLikeDocblockScanner if (strpos($assertion['param_name'], $param->name.'->') === 0) { $storage->assertions[] = new Possibilities( - str_replace($param->name, (string) $i, $assertion['param_name']), + substr_replace($assertion['param_name'], (string) $i, 0, strlen($param->name)), $assertion_type_parts, ); continue 2; @@ -1439,10 +1442,17 @@ class FunctionLikeDocblockScanner if ($template_map[1] !== null && $template_map[2] !== null) { if (trim($template_map[2])) { + $type_string = $template_map[2]; + try { + $type_string = CommentAnalyzer::splitDocLine($type_string)[0]; + } catch (DocblockParseException $e) { + throw new DocblockParseException($type_string . ' is not a valid type: '.$e->getMessage()); + } + $type_string = CommentAnalyzer::sanitizeDocblockType($type_string); try { $template_type = TypeParser::parseTokens( TypeTokenizer::getFullyQualifiedTokens( - $template_map[2], + $type_string, $aliases, $storage->template_types + ($template_types ?: []), $type_aliases, diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php index 4a4779d3..989bae6e 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php @@ -238,6 +238,12 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements FileSour $var_id = '$' . $var->name; $functionlike_node_scanner->storage->global_variables[$var_id] = true; + + if (isset($this->codebase->config->globals[$var_id])) { + $var_type = Type::parseString($this->codebase->config->globals[$var_id]); + /** @psalm-suppress UnusedMethodCall */ + $var_type->queueClassLikesForScanning($this->codebase, $this->file_storage); + } } } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php index 5e9d9e5a..9b8c8261 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php @@ -49,10 +49,14 @@ class ClassLikeStorageProvider return self::$storage[$fq_classlike_name_lc]; } + /** + * @psalm-mutation-free + */ public function has(string $fq_classlike_name): bool { $fq_classlike_name_lc = strtolower($fq_classlike_name); + /** @psalm-suppress ImpureStaticProperty Used only for caching */ return isset(self::$storage[$fq_classlike_name_lc]); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FakeFileProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FakeFileProvider.php index 47dcb7c5..64251084 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FakeFileProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FakeFileProvider.php @@ -20,16 +20,26 @@ class FakeFileProvider extends FileProvider */ public array $fake_file_times = []; + /** + * @var array + */ + public array $fake_directories = []; + public function fileExists(string $file_path): bool { return isset($this->fake_files[$file_path]) || parent::fileExists($file_path); } + public function isDirectory(string $file_path): bool + { + return isset($this->fake_directories[$file_path]) || parent::isDirectory($file_path); + } + /** @psalm-external-mutation-free */ public function getContents(string $file_path, bool $go_to_source = false): string { if (!$go_to_source && isset($this->temp_files[$file_path])) { - return $this->temp_files[$file_path]; + return $this->temp_files[$file_path]['content']; } return $this->fake_files[$file_path] ?? parent::getContents($file_path); @@ -40,10 +50,10 @@ class FakeFileProvider extends FileProvider $this->fake_files[$file_path] = $file_contents; } - public function setOpenContents(string $file_path, string $file_contents): void + public function setOpenContents(string $file_path, ?string $file_contents = null): void { if (isset($this->fake_files[$file_path])) { - $this->fake_files[$file_path] = $file_contents; + $this->fake_files[$file_path] = $file_contents ?? $this->getContents($file_path, true); } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileProvider.php index 13fcf572..aa4202d0 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FileProvider.php @@ -24,7 +24,7 @@ use const DIRECTORY_SEPARATOR; class FileProvider { /** - * @var array + * @var array */ protected array $temp_files = []; @@ -33,32 +33,31 @@ class FileProvider */ protected static array $open_files = []; - /** @psalm-mutation-free */ + /** + * @var array + */ + protected array $open_files_paths = []; + public function getContents(string $file_path, bool $go_to_source = false): string { if (!$go_to_source && isset($this->temp_files[$file_path])) { - return $this->temp_files[$file_path]; + return $this->temp_files[$file_path]['content']; } - /** @psalm-suppress ImpureStaticProperty Used only for caching */ if (isset(self::$open_files[$file_path])) { return self::$open_files[$file_path]; } - /** @psalm-suppress ImpureFunctionCall For our purposes, this should not mutate external state */ if (!file_exists($file_path)) { throw new UnexpectedValueException('File ' . $file_path . ' should exist to get contents'); } - /** @psalm-suppress ImpureFunctionCall For our purposes, this should not mutate external state */ if (is_dir($file_path)) { throw new UnexpectedValueException('File ' . $file_path . ' is a directory'); } - /** @psalm-suppress ImpureFunctionCall For our purposes, this should not mutate external state */ $file_contents = (string) file_get_contents($file_path); - /** @psalm-suppress ImpureStaticProperty Used only for caching */ self::$open_files[$file_path] = $file_contents; return $file_contents; @@ -71,16 +70,19 @@ class FileProvider } if (isset($this->temp_files[$file_path])) { - $this->temp_files[$file_path] = $file_contents; + $this->temp_files[$file_path] = [ + 'version'=> null, + 'content' => $file_contents, + ]; } file_put_contents($file_path, $file_contents); } - public function setOpenContents(string $file_path, string $file_contents): void + public function setOpenContents(string $file_path, ?string $file_contents = null): void { if (isset(self::$open_files[$file_path])) { - self::$open_files[$file_path] = $file_contents; + self::$open_files[$file_path] = $file_contents ?? $this->getContents($file_path, true); } } @@ -93,9 +95,19 @@ class FileProvider return (int) filemtime($file_path); } - public function addTemporaryFileChanges(string $file_path, string $new_content): void + public function addTemporaryFileChanges(string $file_path, string $new_content, ?int $version = null): void { - $this->temp_files[$file_path] = $new_content; + if (isset($this->temp_files[$file_path]) && + $version !== null && + $this->temp_files[$file_path]['version'] !== null && + $version < $this->temp_files[$file_path]['version'] + ) { + return; + } + $this->temp_files[$file_path] = [ + 'version' => $version, + 'content' => $new_content, + ]; } public function removeTemporaryFileChanges(string $file_path): void @@ -103,9 +115,15 @@ class FileProvider unset($this->temp_files[$file_path]); } + public function getOpenFilesPath(): array + { + return $this->open_files_paths; + } + public function openFile(string $file_path): void { self::$open_files[$file_path] = $this->getContents($file_path, true); + $this->open_files_paths[$file_path] = $file_path; } public function isOpen(string $file_path): bool @@ -115,7 +133,11 @@ class FileProvider public function closeFile(string $file_path): void { - unset($this->temp_files[$file_path], self::$open_files[$file_path]); + unset( + $this->temp_files[$file_path], + self::$open_files[$file_path], + $this->open_files_paths[$file_path], + ); } public function fileExists(string $file_path): bool @@ -123,6 +145,11 @@ class FileProvider return file_exists($file_path); } + public function isDirectory(string $file_path): bool + { + return is_dir($file_path); + } + /** * @param array $file_extensions * @param null|callable(string):bool $filter diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php index bdd59a0a..de1e27d7 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php @@ -22,8 +22,8 @@ use Psalm\Internal\Provider\ReturnTypeProvider\ArrayReduceReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\ArrayReverseReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\ArraySliceReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\ArraySpliceReturnTypeProvider; -use Psalm\Internal\Provider\ReturnTypeProvider\ArrayUniqueReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\BasenameReturnTypeProvider; +use Psalm\Internal\Provider\ReturnTypeProvider\DateReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\DirnameReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\FilterVarReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\FirstArgStringReturnTypeProvider; @@ -36,6 +36,7 @@ use Psalm\Internal\Provider\ReturnTypeProvider\MbInternalEncodingReturnTypeProvi use Psalm\Internal\Provider\ReturnTypeProvider\MinMaxReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\MktimeReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\ParseUrlReturnTypeProvider; +use Psalm\Internal\Provider\ReturnTypeProvider\PowReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\RandReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\RoundReturnTypeProvider; use Psalm\Internal\Provider\ReturnTypeProvider\StrReplaceReturnTypeProvider; @@ -81,7 +82,6 @@ class FunctionReturnTypeProvider $this->registerClass(ArraySliceReturnTypeProvider::class); $this->registerClass(ArraySpliceReturnTypeProvider::class); $this->registerClass(ArrayReverseReturnTypeProvider::class); - $this->registerClass(ArrayUniqueReturnTypeProvider::class); $this->registerClass(ArrayFillReturnTypeProvider::class); $this->registerClass(ArrayFillKeysReturnTypeProvider::class); $this->registerClass(FilterVarReturnTypeProvider::class); @@ -103,6 +103,8 @@ class FunctionReturnTypeProvider $this->registerClass(InArrayReturnTypeProvider::class); $this->registerClass(RoundReturnTypeProvider::class); $this->registerClass(MbInternalEncodingReturnTypeProvider::class); + $this->registerClass(DateReturnTypeProvider::class); + $this->registerClass(PowReturnTypeProvider::class); } /** diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayUniqueReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayUniqueReturnTypeProvider.php deleted file mode 100644 index 1b46a3fb..00000000 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayUniqueReturnTypeProvider.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ - public static function getFunctionIds(): array - { - return ['array_unique']; - } - - public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): Union - { - $statements_source = $event->getStatementsSource(); - $call_args = $event->getCallArgs(); - if (!$statements_source instanceof StatementsAnalyzer) { - return Type::getMixed(); - } - - $first_arg = $call_args[0]->value ?? null; - - $first_arg_array = $first_arg - && ($first_arg_type = $statements_source->node_data->getType($first_arg)) - && $first_arg_type->hasType('array') - && ($array_atomic_type = $first_arg_type->getArray()) - && ($array_atomic_type instanceof TArray - || $array_atomic_type instanceof TKeyedArray) - ? $array_atomic_type - : null; - - if (!$first_arg_array) { - return Type::getArray(); - } - - if ($first_arg_array instanceof TArray) { - if ($first_arg_array instanceof TNonEmptyArray) { - $first_arg_array = $first_arg_array->setCount(null); - } - - return new Union([$first_arg_array]); - } - - return new Union([$first_arg_array->getGenericArrayType()]); - } -} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/DateReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/DateReturnTypeProvider.php new file mode 100644 index 00000000..13bc381d --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/DateReturnTypeProvider.php @@ -0,0 +1,69 @@ + + */ + public static function getFunctionIds(): array + { + return ['date', 'gmdate']; + } + + public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): ?Union + { + $source = $event->getStatementsSource(); + if (!$source instanceof StatementsAnalyzer) { + return null; + } + + $call_args = $event->getCallArgs(); + + $format_type = Type::getString(); + if (isset($call_args[0])) { + $type = $source->node_data->getType($call_args[0]->value); + if ($type !== null + && $type->isSingleStringLiteral() + && is_numeric(date($type->getSingleStringLiteral()->value)) + ) { + $format_type = Type::getNumericString(); + } + } + + if (!isset($call_args[1])) { + return $format_type; + } + + $type = $source->node_data->getType($call_args[1]->value); + if ($type !== null && $type->isSingle()) { + $atomic_type = array_values($type->getAtomicTypes())[0]; + if ($atomic_type instanceof Type\Atomic\TNumeric + || $atomic_type instanceof Type\Atomic\TInt + || $atomic_type instanceof TLiteralInt + || ($atomic_type instanceof TLiteralString && is_numeric($atomic_type->value)) + ) { + return $format_type; + } + } + return $format_type; + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/PowReturnTypeProvider.php b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/PowReturnTypeProvider.php new file mode 100644 index 00000000..bffd07fc --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ReturnTypeProvider/PowReturnTypeProvider.php @@ -0,0 +1,92 @@ + + */ + public static function getFunctionIds(): array + { + return ['pow']; + } + + public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): ?Union + { + $call_args = $event->getCallArgs(); + + if (count($call_args) !== 2) { + return null; + } + + $first_arg = $event->getStatementsSource()->getNodeTypeProvider()->getType($call_args[0]->value); + $second_arg = $event->getStatementsSource()->getNodeTypeProvider()->getType($call_args[1]->value); + + $first_arg_literal = null; + $first_arg_is_int = false; + $first_arg_is_float = false; + if ($first_arg !== null && $first_arg->isSingle()) { + $first_atomic_type = $first_arg->getSingleAtomic(); + if ($first_atomic_type instanceof TInt) { + $first_arg_is_int = true; + } elseif ($first_atomic_type instanceof TFloat) { + $first_arg_is_float = true; + } + if ($first_atomic_type instanceof TLiteralInt + || $first_atomic_type instanceof TLiteralFloat + ) { + $first_arg_literal = $first_atomic_type->value; + } + } + + $second_arg_literal = null; + $second_arg_is_int = false; + $second_arg_is_float = false; + if ($second_arg !== null && $second_arg->isSingle()) { + $second_atomic_type = $second_arg->getSingleAtomic(); + if ($second_atomic_type instanceof TInt) { + $second_arg_is_int = true; + } elseif ($second_atomic_type instanceof TFloat) { + $second_arg_is_float = true; + } + if ($second_atomic_type instanceof TLiteralInt + || $second_atomic_type instanceof TLiteralFloat + ) { + $second_arg_literal = $second_atomic_type->value; + } + } + + if ($first_arg_literal === 0) { + return Type::getInt(true, 0); + } + if ($second_arg_literal === 0) { + return Type::getInt(true, 1); + } + if ($first_arg_literal !== null && $second_arg_literal !== null) { + return Type::getFloat($first_arg_literal ** $second_arg_literal); + } + if ($first_arg_is_int && $second_arg_is_int) { + return Type::getInt(); + } + if ($first_arg_is_float || $second_arg_is_float) { + return Type::getFloat(); + } + + return new Union([new TInt(), new TFloat()]); + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/ClassLikeDocblockComment.php b/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/ClassLikeDocblockComment.php index fc0a83c9..0d68ece0 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/ClassLikeDocblockComment.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/ClassLikeDocblockComment.php @@ -63,9 +63,9 @@ class ClassLikeDocblockComment */ public array $methods = []; - public bool $sealed_properties = false; + public ?bool $sealed_properties = null; - public bool $sealed_methods = false; + public ?bool $sealed_methods = null; public bool $override_property_visibility = false; @@ -87,6 +87,8 @@ class ClassLikeDocblockComment */ public array $imported_types = []; + public ?string $inheritors = null; + public bool $consistent_constructor = false; public bool $consistent_templates = false; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumNameFetch.php b/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumNameFetch.php new file mode 100644 index 00000000..29639fb3 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumNameFetch.php @@ -0,0 +1,11 @@ +fqcln = $fqcln; + $this->case = $case; + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumValueFetch.php b/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumValueFetch.php new file mode 100644 index 00000000..1ee9c003 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumValueFetch.php @@ -0,0 +1,11 @@ +key = $key; $this->value = $value; $this->is_list = $is_list; + $this->count = $count; } /** @@ -37,18 +43,35 @@ class ArrayType public static function infer(Atomic $type): ?self { if ($type instanceof TKeyedArray) { + $count = null; + if ($type->isSealed()) { + $count = count($type->properties); + } + return new self( $type->getGenericKeyType(), $type->getGenericValueType(), $type->is_list, + $count, ); } - if ($type instanceof TArray) { + if ($type instanceof TNonEmptyArray) { return new self( $type->type_params[0], $type->type_params[1], false, + $type->count, + ); + } + + if ($type instanceof TArray) { + $empty = $type->isEmptyArray(); + return new self( + $type->type_params[0], + $type->type_params[1], + false, + $empty?0:null, ); } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php index b0f461cc..e01ee2d2 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php @@ -4,6 +4,7 @@ namespace Psalm\Internal\Type\Comparator; use Psalm\Codebase; use Psalm\Internal\MethodIdentifier; +use Psalm\Type; use Psalm\Type\Atomic; use Psalm\Type\Atomic\Scalar; use Psalm\Type\Atomic\TArray; @@ -17,15 +18,18 @@ use Psalm\Type\Atomic\TConditional; use Psalm\Type\Atomic\TEmptyMixed; use Psalm\Type\Atomic\TEnumCase; use Psalm\Type\Atomic\TGenericObject; +use Psalm\Type\Atomic\TInt; use Psalm\Type\Atomic\TIterable; use Psalm\Type\Atomic\TKeyOf; use Psalm\Type\Atomic\TKeyedArray; use Psalm\Type\Atomic\TList; +use Psalm\Type\Atomic\TLiteralInt; use Psalm\Type\Atomic\TLiteralString; use Psalm\Type\Atomic\TMixed; use Psalm\Type\Atomic\TNamedObject; use Psalm\Type\Atomic\TNever; use Psalm\Type\Atomic\TNonEmptyArray; +use Psalm\Type\Atomic\TNonEmptyMixed; use Psalm\Type\Atomic\TNull; use Psalm\Type\Atomic\TObject; use Psalm\Type\Atomic\TObjectWithProperties; @@ -35,12 +39,14 @@ use Psalm\Type\Atomic\TTemplateKeyOf; use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Atomic\TTemplateValueOf; use Psalm\Type\Atomic\TValueOf; +use Psalm\Type\Union; use function array_merge; use function array_values; use function assert; use function count; use function get_class; +use function is_int; use function strtolower; /** @@ -81,14 +87,43 @@ class AtomicTypeComparator ); } + if ($input_type_part instanceof TValueOf) { + if ($container_type_part instanceof TValueOf) { + return UnionTypeComparator::isContainedBy( + $codebase, + $input_type_part->type, + $container_type_part->type, + false, + false, + null, + false, + false, + ); + } elseif ($container_type_part instanceof Scalar) { + return UnionTypeComparator::isContainedBy( + $codebase, + TValueOf::getValueType($input_type_part->type, $codebase) ?? $input_type_part->type, + new Union([$container_type_part]), + false, + false, + null, + false, + false, + ); + } + } + if ($container_type_part instanceof TMixed || ($container_type_part instanceof TTemplateParam && $container_type_part->as->isMixed() && !$container_type_part->extra_types && $input_type_part instanceof TMixed) ) { - if (get_class($container_type_part) === TEmptyMixed::class - && get_class($input_type_part) === TMixed::class + if (get_class($input_type_part) === TMixed::class + && ( + get_class($container_type_part) === TEmptyMixed::class + || get_class($container_type_part) === TNonEmptyMixed::class + ) ) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = true; @@ -298,7 +333,7 @@ class AtomicTypeComparator $atomic_comparison_result->type_coerced = true; } - return false; + return true; } if ($container_type_part instanceof TEnumCase @@ -600,6 +635,40 @@ class AtomicTypeComparator } } + if ($input_type_part instanceof TEnumCase + && $codebase->classlike_storage_provider->has($input_type_part->value) + ) { + if ($container_type_part instanceof TString || $container_type_part instanceof TInt) { + $input_type_classlike_storage = $codebase->classlike_storage_provider->get($input_type_part->value); + if ($input_type_classlike_storage->enum_type === null + || !isset($input_type_classlike_storage->enum_cases[$input_type_part->case_name]) + ) { + // Not a backed enum or non-existent enum case + return false; + } + + $input_type_enum_case_storage = $input_type_classlike_storage->enum_cases[$input_type_part->case_name]; + assert( + $input_type_enum_case_storage->value !== null, + 'Backed enums cannot have values without a value.', + ); + + if (is_int($input_type_enum_case_storage->value)) { + return self::isContainedBy( + $codebase, + new TLiteralInt($input_type_enum_case_storage->value), + $container_type_part, + ); + } + + return self::isContainedBy( + $codebase, + Type::getAtomicStringFromLiteral($input_type_enum_case_storage->value), + $container_type_part, + ); + } + } + if ($container_type_part instanceof TString || $container_type_part instanceof TScalar) { if ($input_type_part instanceof TNamedObject) { // check whether the object has a __toString method diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/ClassLikeStringComparator.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/ClassLikeStringComparator.php index c074efd8..a3830ea8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/ClassLikeStringComparator.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/ClassLikeStringComparator.php @@ -80,7 +80,7 @@ class ClassLikeStringComparator : $input_type_part->value, ); - return AtomicTypeComparator::isContainedBy( + $isContainedBy = AtomicTypeComparator::isContainedBy( $codebase, $fake_input_object, $fake_container_object, @@ -88,5 +88,16 @@ class ClassLikeStringComparator false, $atomic_comparison_result, ); + + if ($atomic_comparison_result + && $atomic_comparison_result->replacement_atomic_type instanceof TNamedObject + ) { + $atomic_comparison_result->replacement_atomic_type = new TClassString( + 'object', + $atomic_comparison_result->replacement_atomic_type, + ); + } + + return $isContainedBy; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/KeyedArrayComparator.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/KeyedArrayComparator.php index 9eba8781..c9d7aad5 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/KeyedArrayComparator.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/KeyedArrayComparator.php @@ -3,11 +3,15 @@ namespace Psalm\Internal\Type\Comparator; use Psalm\Codebase; +use Psalm\Internal\Type\TemplateInferredTypeReplacer; +use Psalm\Internal\Type\TemplateResult; use Psalm\Type; use Psalm\Type\Atomic; +use Psalm\Type\Atomic\TGenericObject; use Psalm\Type\Atomic\TKeyedArray; use Psalm\Type\Atomic\TNamedObject; use Psalm\Type\Atomic\TObjectWithProperties; +use Psalm\Type\Union; use function array_keys; use function is_string; @@ -84,24 +88,47 @@ class KeyedArrayComparator $property_type_comparison, $allow_interface_equality, ); - if (!$is_input_containedby_container && !$property_type_comparison->type_coerced_from_scalar) { - $inverse_property_type_comparison = new TypeComparisonResult(); - + if (!$is_input_containedby_container) { if ($atomic_comparison_result) { - if (UnionTypeComparator::isContainedBy( - $codebase, - $container_property_type, - $input_property_type, - false, - false, - $inverse_property_type_comparison, - $allow_interface_equality, - ) - || $inverse_property_type_comparison->type_coerced_from_scalar - ) { - $atomic_comparison_result->type_coerced = true; + $atomic_comparison_result->type_coerced + = $property_type_comparison->type_coerced === true + && $atomic_comparison_result->type_coerced !== false; + + if (!$property_type_comparison->type_coerced_from_scalar + && !$atomic_comparison_result->type_coerced) { + //if we didn't detect a coercion, we try to compare the other way around + $inverse_property_type_comparison = new TypeComparisonResult(); + if (UnionTypeComparator::isContainedBy( + $codebase, + $container_property_type, + $input_property_type, + false, + false, + $inverse_property_type_comparison, + $allow_interface_equality, + ) + || $inverse_property_type_comparison->type_coerced_from_scalar + ) { + $atomic_comparison_result->type_coerced = true; + } } + $atomic_comparison_result->type_coerced_from_mixed + = $property_type_comparison->type_coerced_from_mixed === true + && $atomic_comparison_result->type_coerced_from_mixed !== false; + + $atomic_comparison_result->type_coerced_from_as_mixed + = $property_type_comparison->type_coerced_from_as_mixed === true + && $atomic_comparison_result->type_coerced_from_as_mixed !== false; + + $atomic_comparison_result->type_coerced_from_scalar + = $property_type_comparison->type_coerced_from_scalar === true + && $atomic_comparison_result->type_coerced_from_scalar !== false; + + $atomic_comparison_result->scalar_type_match_found + = $property_type_comparison->scalar_type_match_found === true + && $atomic_comparison_result->scalar_type_match_found !== false; + if ($property_type_comparison->missing_shape_fields) { $atomic_comparison_result->missing_shape_fields = $property_type_comparison->missing_shape_fields; @@ -110,13 +137,10 @@ class KeyedArrayComparator $all_types_contain = false; } else { - if (!$is_input_containedby_container) { - $all_types_contain = false; - } if ($atomic_comparison_result) { $atomic_comparison_result->to_string_cast = $atomic_comparison_result->to_string_cast === true - || $property_type_comparison->to_string_cast === true; + || $property_type_comparison->to_string_cast === true; } } } @@ -127,6 +151,132 @@ class KeyedArrayComparator } return false; } + + // check remaining $input_properties against container's fallback_params + if ($container_type_part instanceof TKeyedArray + && $container_type_part->fallback_params !== null + ) { + [$key_type, $value_type] = $container_type_part->fallback_params; + // treat fallback params as possibly undefined + // otherwise comparison below would fail for list{0?:int} <=> list{..., int>} + // as the latter `int` is not marked as possibly_undefined + $value_type = $value_type->setPossiblyUndefined(true); + + foreach ($input_properties as $key => $input_property_type) { + $key_type_comparison = new TypeComparisonResult(); + if (!UnionTypeComparator::isContainedBy( + $codebase, + is_string($key) ? Type::getString($key) : Type::getInt(false, $key), + $key_type, + false, + false, + $key_type_comparison, + $allow_interface_equality, + )) { + if ($atomic_comparison_result) { + $atomic_comparison_result->type_coerced + = $key_type_comparison->type_coerced === true + && $atomic_comparison_result->type_coerced !== false; + + $atomic_comparison_result->type_coerced_from_mixed + = $key_type_comparison->type_coerced_from_mixed === true + && $atomic_comparison_result->type_coerced_from_mixed !== false; + + $atomic_comparison_result->type_coerced_from_as_mixed + = $key_type_comparison->type_coerced_from_as_mixed === true + && $atomic_comparison_result->type_coerced_from_as_mixed !== false; + + $atomic_comparison_result->type_coerced_from_scalar + = $key_type_comparison->type_coerced_from_scalar === true + && $atomic_comparison_result->type_coerced_from_scalar !== false; + + $atomic_comparison_result->scalar_type_match_found + = $key_type_comparison->scalar_type_match_found === true + && $atomic_comparison_result->scalar_type_match_found !== false; + } + $all_types_contain = false; + } + + $property_type_comparison = new TypeComparisonResult(); + if (!UnionTypeComparator::isContainedBy( + $codebase, + $input_property_type, + $value_type, + false, + false, + $property_type_comparison, + $allow_interface_equality, + )) { + if ($atomic_comparison_result) { + $atomic_comparison_result->type_coerced + = $property_type_comparison->type_coerced === true + && $atomic_comparison_result->type_coerced !== false; + + $atomic_comparison_result->type_coerced_from_mixed + = $property_type_comparison->type_coerced_from_mixed === true + && $atomic_comparison_result->type_coerced_from_mixed !== false; + + $atomic_comparison_result->type_coerced_from_as_mixed + = $property_type_comparison->type_coerced_from_as_mixed === true + && $atomic_comparison_result->type_coerced_from_as_mixed !== false; + + $atomic_comparison_result->type_coerced_from_scalar + = $property_type_comparison->type_coerced_from_scalar === true + && $atomic_comparison_result->type_coerced_from_scalar !== false; + + $atomic_comparison_result->scalar_type_match_found + = $property_type_comparison->scalar_type_match_found === true + && $atomic_comparison_result->scalar_type_match_found !== false; + } + $all_types_contain = false; + } + } + } + + // finally, check input type fallback params against container type fallback params + if ($input_type_part instanceof TKeyedArray + && $container_type_part instanceof TKeyedArray + && $input_type_part->fallback_params !== null + && $container_type_part->fallback_params !== null + ) { + foreach ($input_type_part->fallback_params as $i => $input_param) { + $container_param = $container_type_part->fallback_params[$i]; + $param_comparison = new TypeComparisonResult(); + if (!UnionTypeComparator::isContainedBy( + $codebase, + $input_param, + $container_param, + false, + false, + $param_comparison, + $allow_interface_equality, + )) { + if ($atomic_comparison_result) { + $atomic_comparison_result->type_coerced + = $param_comparison->type_coerced === true + && $atomic_comparison_result->type_coerced !== false; + + $atomic_comparison_result->type_coerced_from_mixed + = $param_comparison->type_coerced_from_mixed === true + && $atomic_comparison_result->type_coerced_from_mixed !== false; + + $atomic_comparison_result->type_coerced_from_as_mixed + = $param_comparison->type_coerced_from_as_mixed === true + && $atomic_comparison_result->type_coerced_from_as_mixed !== false; + + $atomic_comparison_result->type_coerced_from_scalar + = $param_comparison->type_coerced_from_scalar === true + && $atomic_comparison_result->type_coerced_from_scalar !== false; + + $atomic_comparison_result->scalar_type_match_found + = $param_comparison->scalar_type_match_found === true + && $atomic_comparison_result->scalar_type_match_found !== false; + } + $all_types_contain = false; + } + } + } + return $all_types_contain; } @@ -139,36 +289,20 @@ class KeyedArrayComparator ): bool { $all_types_contain = true; + $input_object_with_keys = self::coerceToObjectWithProperties( + $codebase, + $input_type_part, + $container_type_part, + ); + foreach ($container_type_part->properties as $property_name => $container_property_type) { - if (!is_string($property_name)) { - continue; - } - - if (!$codebase->classlikes->classOrInterfaceExists($input_type_part->value)) { + if (!$input_object_with_keys || !isset($input_object_with_keys->properties[$property_name])) { $all_types_contain = false; continue; } - if (!$codebase->properties->propertyExists( - $input_type_part->value . '::$' . $property_name, - true, - )) { - $all_types_contain = false; - - continue; - } - - $property_declaring_class = (string) $codebase->properties->getDeclaringClassForProperty( - $input_type_part . '::$' . $property_name, - true, - ); - - $class_storage = $codebase->classlike_storage_provider->get($property_declaring_class); - - $input_property_storage = $class_storage->properties[$property_name]; - - $input_property_type = $input_property_storage->type ?: Type::getMixed(); + $input_property_type = $input_object_with_keys->properties[$property_name]; $property_type_comparison = new TypeComparisonResult(); @@ -208,4 +342,61 @@ class KeyedArrayComparator return $all_types_contain; } + + public static function coerceToObjectWithProperties( + Codebase $codebase, + TNamedObject $input_type_part, + TObjectWithProperties $container_type_part + ): ?TObjectWithProperties { + $storage = $codebase->classlikes->getStorageFor($input_type_part->value); + + if (!$storage) { + return null; + } + + $inferred_lower_bounds = []; + + if ($input_type_part instanceof TGenericObject) { + foreach ($storage->template_types ?? [] as $template_name => $templates) { + foreach (array_keys($templates) as $offset => $defining_at) { + $inferred_lower_bounds[$template_name][$defining_at] = + $input_type_part->type_params[$offset]; + } + } + } + + foreach ($storage->template_extended_params ?? [] as $defining_at => $templates) { + foreach ($templates as $template_name => $template_atomic) { + $inferred_lower_bounds[$template_name][$defining_at] = $template_atomic; + } + } + + $properties = []; + + foreach ($storage->appearing_property_ids as $property_name => $property_id) { + if (!isset($container_type_part->properties[$property_name])) { + continue; + } + + $property_type = $codebase->properties->hasStorage($property_id) + ? $codebase->properties->getStorage($property_id)->type + : null; + + $properties[$property_name] = $property_type ?? Type::getMixed(); + } + + $replaced_object = TemplateInferredTypeReplacer::replace( + new Union([ + new TObjectWithProperties($properties), + ]), + new TemplateResult( + $storage->template_types ?? [], + $inferred_lower_bounds, + ), + $codebase, + ); + + /** @var TObjectWithProperties */ + return $replaced_object->getSingleAtomic(); + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/ObjectComparator.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/ObjectComparator.php index 2e7b7c76..1d264658 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/ObjectComparator.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/ObjectComparator.php @@ -5,6 +5,7 @@ namespace Psalm\Internal\Type\Comparator; use Psalm\Codebase; use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer; use Psalm\Type\Atomic; +use Psalm\Type\Atomic\TCallableObject; use Psalm\Type\Atomic\TIterable; use Psalm\Type\Atomic\TMixed; use Psalm\Type\Atomic\TNamedObject; @@ -90,6 +91,8 @@ class ObjectComparator $intersection_container_type_lower = 'object'; } elseif ($intersection_container_type instanceof TTemplateParam) { $intersection_container_type_lower = null; + } elseif ($intersection_container_type instanceof TCallableObject) { + $intersection_container_type_lower = 'callable-object'; } else { $container_was_static = $intersection_container_type->is_static; @@ -134,7 +137,7 @@ class ObjectComparator /** * @param TNamedObject|TTemplateParam|TIterable $type_part - * @return array + * @return array */ private static function getIntersectionTypes(Atomic $type_part): array { @@ -166,8 +169,8 @@ class ObjectComparator } /** - * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties $intersection_input_type - * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties $intersection_container_type + * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $intersection_input_type + * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $intersection_container_type */ private static function isIntersectionShallowlyContainedBy( Codebase $codebase, @@ -268,6 +271,8 @@ class ObjectComparator $intersection_input_type_lower = 'iterable'; } elseif ($intersection_input_type instanceof TObjectWithProperties) { $intersection_input_type_lower = 'object'; + } elseif ($intersection_input_type instanceof TCallableObject) { + $intersection_input_type_lower = 'callable-object'; } else { $input_was_static = $intersection_input_type->is_static; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/UnionTypeComparator.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/UnionTypeComparator.php index c4465006..d3c1b457 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/UnionTypeComparator.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/Comparator/UnionTypeComparator.php @@ -44,7 +44,7 @@ class UnionTypeComparator bool $allow_interface_equality = false, bool $allow_float_int_equality = true ): bool { - if ($container_type->isMixed()) { + if ($container_type->isVanillaMixed()) { return true; } @@ -63,9 +63,6 @@ class UnionTypeComparator return false; } - if ($container_type->hasMixed() && !$container_type->isEmptyMixed()) { - return true; - } $container_has_template = $container_type->hasTemplateOrStatic(); @@ -178,7 +175,7 @@ class UnionTypeComparator if ($container_required_param_count > $input_all_param_count || $container_all_param_count < $input_required_param_count ) { - return false; + continue; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/NegatedAssertionReconciler.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/NegatedAssertionReconciler.php index 5e1d994e..3ce8aedd 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/NegatedAssertionReconciler.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/NegatedAssertionReconciler.php @@ -182,6 +182,10 @@ class NegatedAssertionReconciler extends Reconciler ) { $existing_var_type->removeType('array-key'); $existing_var_type->addType(new TString); + } elseif ($assertion_type instanceof TNonEmptyString + && $existing_var_type->hasString() + ) { + // do nothing } elseif ($assertion instanceof IsClassNotEqual) { // do nothing } elseif ($assertion_type instanceof TClassString && $assertion_type->is_loaded) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/ParseTreeCreator.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/ParseTreeCreator.php index 34502e11..9fdd3fcc 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/ParseTreeCreator.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/ParseTreeCreator.php @@ -64,11 +64,14 @@ class ParseTreeCreator $type_token = $this->type_tokens[$this->t]; switch ($type_token[0]) { - case '<': case '{': case ']': throw new TypeParseTreeException('Unexpected token ' . $type_token[0]); + case '<': + $this->handleLessThan(); + break; + case '[': $this->handleOpenSquareBracket(); break; @@ -232,6 +235,29 @@ class ParseTreeCreator $this->current_leaf = $new_parent_leaf; } + private function handleLessThan(): void + { + if (!$this->current_leaf instanceof FieldEllipsis) { + throw new TypeParseTreeException('Unexpected token <'); + } + + $current_parent = $this->current_leaf->parent; + + if (!$current_parent instanceof KeyedArrayTree) { + throw new TypeParseTreeException('Unexpected token <'); + } + + array_pop($current_parent->children); + + $generic_leaf = new GenericTree( + '', + $current_parent, + ); + $current_parent->children []= $generic_leaf; + + $this->current_leaf = $generic_leaf; + } + private function handleOpenSquareBracket(): void { if ($this->current_leaf instanceof Root) { diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/SimpleAssertionReconciler.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/SimpleAssertionReconciler.php index 44adb58d..57dd5c2b 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/SimpleAssertionReconciler.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/SimpleAssertionReconciler.php @@ -28,6 +28,7 @@ use Psalm\Storage\Assertion\NonEmpty; use Psalm\Storage\Assertion\NonEmptyCountable; use Psalm\Storage\Assertion\Truthy; use Psalm\Type; +use Psalm\Type\Atomic; use Psalm\Type\Atomic\Scalar; use Psalm\Type\Atomic\TArray; use Psalm\Type\Atomic\TArrayKey; @@ -71,11 +72,13 @@ use Psalm\Type\Atomic\TScalar; use Psalm\Type\Atomic\TString; use Psalm\Type\Atomic\TTemplateParam; use Psalm\Type\Atomic\TTrue; +use Psalm\Type\Atomic\TValueOf; use Psalm\Type\Reconciler; use Psalm\Type\Union; use function array_map; use function array_merge; +use function array_values; use function assert; use function count; use function explode; @@ -290,7 +293,9 @@ class SimpleAssertionReconciler extends Reconciler if ($assertion_type instanceof TObject) { return self::reconcileObject( + $codebase, $assertion, + $assertion_type, $existing_var_type, $key, $negated, @@ -527,6 +532,10 @@ class SimpleAssertionReconciler extends Reconciler } } + if ($assertion_type instanceof TValueOf) { + return $assertion_type->type; + } + return null; } @@ -1574,7 +1583,9 @@ class SimpleAssertionReconciler extends Reconciler * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileObject( + Codebase $codebase, Assertion $assertion, + TObject $assertion_type, Union $existing_var_type, ?string $key, bool $negated, @@ -1593,11 +1604,25 @@ class SimpleAssertionReconciler extends Reconciler $object_types = []; $redundant = true; + $assertion_type_is_intersectable_type = Type::isIntersectionType($assertion_type); foreach ($existing_var_atomic_types as $type) { - if ($type->isObjectType()) { - $object_types[] = $type; + if ($assertion_type_is_intersectable_type + && self::areIntersectionTypesAllowed($codebase, $type) + ) { + /** @var TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $assertion_type */ + $object_types[] = $type->addIntersectionType($assertion_type); + $redundant = false; + } elseif ($type->isObjectType()) { + if ($assertion_type_is_intersectable_type + && !self::areIntersectionTypesAllowed($codebase, $type) + ) { + $redundant = false; + } else { + $object_types[] = $type; + } } elseif ($type instanceof TCallable) { - $object_types[] = new TCallableObject(); + $callable_object = new TCallableObject($type->from_docblock, $type); + $object_types[] = $callable_object; $redundant = false; } elseif ($type instanceof TTemplateParam && $type->as->isMixed() @@ -1607,8 +1632,17 @@ class SimpleAssertionReconciler extends Reconciler $redundant = false; } elseif ($type instanceof TTemplateParam) { if ($type->as->hasObject() || $type->as->hasMixed()) { - $type = $type->replaceAs(self::reconcileObject( + /** + * @psalm-suppress PossiblyInvalidArgument This looks wrong, psalm assumes that $assertion_type + * can contain TNamedObject due to the reconciliation above + * regarding {@see Type::isIntersectionType}. Due to the + * native argument type `TObject`, the variable object will + * never be `TNamedObject`. + */ + $reconciled_type = self::reconcileObject( + $codebase, $assertion, + $assertion_type, $type->as, null, false, @@ -1616,7 +1650,8 @@ class SimpleAssertionReconciler extends Reconciler $suppressed_issues, $failed_reconciliation, $is_equality, - )); + ); + $type = $type->replaceAs($reconciled_type); $object_types[] = $type; } @@ -2894,19 +2929,41 @@ class SimpleAssertionReconciler extends Reconciler int &$failed_reconciliation ): Union { $class_name = $class_constant_expression->fq_classlike_name; - $constant_pattern = $class_constant_expression->const_name; - - $resolver = new ClassConstantByWildcardResolver($codebase); - $matched_class_constant_types = $resolver->resolve($class_name, $constant_pattern); - if ($matched_class_constant_types === null) { + if (!$codebase->classlike_storage_provider->has($class_name)) { return $existing_type; } - if ($matched_class_constant_types === []) { + $constant_pattern = $class_constant_expression->const_name; + + $resolver = new ClassConstantByWildcardResolver($codebase); + $matched_class_constant_types = $resolver->resolve( + $class_name, + $constant_pattern, + ); + + if ($matched_class_constant_types === null) { $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } - return TypeCombiner::combine($matched_class_constant_types, $codebase); + return TypeCombiner::combine(array_values($matched_class_constant_types), $codebase); + } + + /** + * @psalm-assert-if-true TCallableObject|TObjectWithProperties|TNamedObject $type + */ + private static function areIntersectionTypesAllowed(Codebase $codebase, Atomic $type): bool + { + if ($type instanceof TObjectWithProperties || $type instanceof TCallableObject) { + return true; + } + + if (!$type instanceof TNamedObject || !$codebase->classlike_storage_provider->has($type->value)) { + return false; + } + + $class_storage = $codebase->classlike_storage_provider->get($type->value); + + return !$class_storage->final; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php index e5a85ddd..e824e76f 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php @@ -7,6 +7,7 @@ use Psalm\Codebase; use Psalm\Internal\Analyzer\StatementsAnalyzer; use Psalm\Internal\Codebase\Methods; use Psalm\Internal\Type\Comparator\CallableTypeComparator; +use Psalm\Internal\Type\Comparator\KeyedArrayComparator; use Psalm\Internal\Type\Comparator\UnionTypeComparator; use Psalm\Type; use Psalm\Type\Atomic; @@ -33,7 +34,6 @@ use Psalm\Type\Atomic\TTemplateParamClass; use Psalm\Type\Atomic\TTemplatePropertiesOf; use Psalm\Type\Atomic\TTemplateValueOf; use Psalm\Type\Union; -use Throwable; use function array_fill; use function array_keys; @@ -231,6 +231,17 @@ class TemplateStandinTypeReplacer ); } + if ($atomic_type instanceof TTemplateParam + && isset($template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class]) + ) { + $most_specific_type = self::getMostSpecificTypeFromBounds( + $template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class], + $codebase, + ); + + return array_values($most_specific_type->getAtomicTypes()); + } + if ($atomic_type instanceof TTemplateParamClass && isset($template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class]) ) { @@ -259,11 +270,14 @@ class TemplateStandinTypeReplacer $include_first = true; - if (isset($template_result->template_types[$atomic_type->array_param_name][$atomic_type->defining_class]) + if (isset($template_result->lower_bounds[$atomic_type->array_param_name][$atomic_type->defining_class]) && !empty($template_result->lower_bounds[$atomic_type->offset_param_name]) ) { $array_template_type - = $template_result->template_types[$atomic_type->array_param_name][$atomic_type->defining_class]; + = self::getMostSpecificTypeFromBounds( + $template_result->lower_bounds[$atomic_type->array_param_name][$atomic_type->defining_class], + $codebase, + ); $offset_template_type = self::getMostSpecificTypeFromBounds( array_values($template_result->lower_bounds[$atomic_type->offset_param_name])[0], @@ -317,10 +331,18 @@ class TemplateStandinTypeReplacer $atomic_types = []; $include_first = true; + $template_type = null; - if (isset($template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class])) { + if (isset($template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class])) { + $template_type = self::getMostSpecificTypeFromBounds( + $template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class], + $codebase, + ); + } elseif (isset($template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class])) { $template_type = $template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class]; + } + if ($template_type) { foreach ($template_type->getAtomicTypes() as $template_atomic) { if ($template_atomic instanceof TList) { $template_atomic = $template_atomic->getKeyedArray(); @@ -563,7 +585,7 @@ class TemplateStandinTypeReplacer if (!empty($classlike_storage->template_extended_params[$base_type->value])) { $atomic_input_type = new TGenericObject( - $atomic_input_type->value, + $base_type->value, array_values($classlike_storage->template_extended_params[$base_type->value]), ); @@ -582,6 +604,22 @@ class TemplateStandinTypeReplacer } } + if ($atomic_input_type instanceof TNamedObject + && $base_type instanceof TObjectWithProperties + ) { + $object_with_keys = KeyedArrayComparator::coerceToObjectWithProperties( + $codebase, + $atomic_input_type, + $base_type, + ); + + if ($object_with_keys) { + $matching_atomic_types[$object_with_keys->getId()] = $object_with_keys; + } + + continue; + } + if ($atomic_input_type instanceof TTemplateParam) { $matching_atomic_types = array_merge( $matching_atomic_types, @@ -1233,13 +1271,13 @@ class TemplateStandinTypeReplacer $input_type_params = []; } - try { - $input_class_storage = $codebase->classlike_storage_provider->get($input_type_part->value); - $container_class_storage = $codebase->classlike_storage_provider->get($container_type_part->value); - $container_type_params_covariant = $container_class_storage->template_covariants; - } catch (Throwable $e) { - $input_class_storage = null; - } + $input_class_storage = $codebase->classlike_storage_provider->has($input_type_part->value) + ? $codebase->classlike_storage_provider->get($input_type_part->value) + : null; + + $container_type_params_covariant = $codebase->classlike_storage_provider->has($container_type_part->value) + ? $codebase->classlike_storage_provider->get($container_type_part->value)->template_covariants + : null; if ($input_type_part->value !== $container_type_part->value && $input_class_storage @@ -1266,8 +1304,12 @@ class TemplateStandinTypeReplacer $template_extends = $input_class_storage->template_extended_params; - if (isset($template_extends[$container_type_part->value])) { - $params = $template_extends[$container_type_part->value]; + $container_type_part_value = $container_type_part->value === 'iterable' + ? 'Traversable' + : $container_type_part->value; + + if (isset($template_extends[$container_type_part_value])) { + $params = $template_extends[$container_type_part_value]; $new_input_params = []; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeCombiner.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeCombiner.php index 85aad52b..0daa9d29 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeCombiner.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeCombiner.php @@ -551,6 +551,8 @@ class TypeCombiner } foreach ($type->type_params as $i => $type_param) { + // See https://github.com/vimeo/psalm/pull/9439#issuecomment-1464563015 + /** @psalm-suppress PropertyTypeCoercion */ $combination->array_type_params[$i] = Type::combineUnionTypes( $combination->array_type_params[$i] ?? null, $type_param, @@ -599,6 +601,8 @@ class TypeCombiner if ($type instanceof TClassStringMap) { foreach ([$type->getStandinKeyParam(), $type->value_param] as $i => $type_param) { + // See https://github.com/vimeo/psalm/pull/9439#issuecomment-1464563015 + /** @psalm-suppress PropertyTypeCoercion */ $combination->array_type_params[$i] = Type::combineUnionTypes( $combination->array_type_params[$i] ?? null, $type_param, @@ -1047,19 +1051,25 @@ class TypeCombiner if (!isset($combination->value_types['string'])) { if ($combination->strings) { if ($type instanceof TNumericString) { - $has_non_numeric_string = false; + $has_only_numeric_strings = true; + $has_only_non_empty_strings = true; foreach ($combination->strings as $string_type) { if (!is_numeric($string_type->value)) { - $has_non_numeric_string = true; - break; + $has_only_numeric_strings = false; + } + + if ($string_type->value === '') { + $has_only_non_empty_strings = false; } } - if ($has_non_numeric_string) { - $combination->value_types['string'] = new TString(); - } else { + if ($has_only_numeric_strings) { $combination->value_types['string'] = $type; + } elseif ($has_only_non_empty_strings) { + $combination->value_types['string'] = new TNonEmptyString(); + } else { + $combination->value_types['string'] = new TString(); } } elseif ($type instanceof TLowercaseString) { $has_non_lowercase_string = false; diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeExpander.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeExpander.php index 6a521522..e329f92b 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeExpander.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeExpander.php @@ -6,9 +6,6 @@ use Psalm\Codebase; use Psalm\Exception\CircularReferenceException; use Psalm\Exception\UnresolvableConstantException; use Psalm\Internal\Analyzer\Statements\Expression\Fetch\AtomicPropertyFetchAnalyzer; -use Psalm\Internal\Type\SimpleAssertionReconciler; -use Psalm\Internal\Type\SimpleNegatedAssertionReconciler; -use Psalm\Internal\Type\TypeParser; use Psalm\Storage\Assertion\IsType; use Psalm\Type; use Psalm\Type\Atomic; @@ -18,6 +15,7 @@ use Psalm\Type\Atomic\TClassConstant; use Psalm\Type\Atomic\TClassString; use Psalm\Type\Atomic\TClosure; use Psalm\Type\Atomic\TConditional; +use Psalm\Type\Atomic\TEnumCase; use Psalm\Type\Atomic\TGenericObject; use Psalm\Type\Atomic\TInt; use Psalm\Type\Atomic\TIntMask; @@ -41,7 +39,6 @@ use Psalm\Type\Union; use ReflectionProperty; use function array_filter; -use function array_keys; use function array_map; use function array_merge; use function array_values; @@ -49,9 +46,7 @@ use function count; use function get_class; use function is_string; use function reset; -use function strpos; use function strtolower; -use function substr; /** * @internal @@ -77,8 +72,6 @@ class TypeExpander ): Union { $new_return_type_parts = []; - $had_split_values = false; - foreach ($return_type->getAtomicTypes() as $return_type_part) { $parts = self::expandAtomic( $codebase, @@ -94,21 +87,13 @@ class TypeExpander $throw_on_unresolvable_constant, ); - if ($return_type_part instanceof TTypeAlias || count($parts) > 1) { - $had_split_values = true; - } - $new_return_type_parts = [...$new_return_type_parts, ...$parts]; } - if ($had_split_values) { - $fleshed_out_type = TypeCombiner::combine( - $new_return_type_parts, - $codebase, - ); - } else { - $fleshed_out_type = new Union($new_return_type_parts); - } + $fleshed_out_type = TypeCombiner::combine( + $new_return_type_parts, + $codebase, + ); $fleshed_out_type->from_docblock = $return_type->from_docblock; $fleshed_out_type->ignore_nullable_issues = $return_type->ignore_nullable_issues; @@ -146,6 +131,10 @@ class TypeExpander bool $expand_templates = false, bool $throw_on_unresolvable_constant = false ): array { + if ($return_type instanceof TEnumCase) { + return [$return_type]; + } + if ($return_type instanceof TNamedObject || $return_type instanceof TTemplateParam ) { @@ -260,52 +249,18 @@ class TypeExpander return [new TLiteralClassString($return_type->fq_classlike_name)]; } - $class_storage = $codebase->classlike_storage_provider->get($return_type->fq_classlike_name); - - if (strpos($return_type->const_name, '*') !== false) { - $matching_constants = [ - ...array_keys($class_storage->constants), - ...array_keys($class_storage->enum_cases), - ]; - - $const_name_part = substr($return_type->const_name, 0, -1); - - if ($const_name_part) { - $matching_constants = array_filter( - $matching_constants, - static fn($constant_name): bool => $constant_name !== $const_name_part - && strpos($constant_name, $const_name_part) === 0 - ); - } - } else { - $matching_constants = [$return_type->const_name]; + try { + $class_constant = $codebase->classlikes->getClassConstantType( + $return_type->fq_classlike_name, + $return_type->const_name, + ReflectionProperty::IS_PRIVATE, + ); + } catch (CircularReferenceException $e) { + $class_constant = null; } - $matching_constant_types = []; - - foreach ($matching_constants as $matching_constant) { - try { - $class_constant = $codebase->classlikes->getClassConstantType( - $return_type->fq_classlike_name, - $matching_constant, - ReflectionProperty::IS_PRIVATE, - ); - } catch (CircularReferenceException $e) { - $class_constant = null; - } - - if ($class_constant) { - if ($class_constant->isSingle()) { - $matching_constant_types = array_merge( - array_values($class_constant->getAtomicTypes()), - $matching_constant_types, - ); - } - } - } - - if ($matching_constant_types) { - return $matching_constant_types; + if ($class_constant) { + return array_values($class_constant->getAtomicTypes()); } } @@ -369,6 +324,7 @@ class TypeExpander ]; } + /** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */ foreach ($return_type->extra_types ?? [] as $alias) { $more_recursively_fleshed_out_types = self::expandAtomic( $codebase, @@ -1102,7 +1058,7 @@ class TypeExpander } if ($throw_on_unresolvable_constant - && !$codebase->classOrInterfaceExists($type_param->fq_classlike_name) + && !$codebase->classOrInterfaceOrEnumExists($type_param->fq_classlike_name) ) { throw new UnresolvableConstantException($type_param->fq_classlike_name, $type_param->const_name); } @@ -1112,6 +1068,10 @@ class TypeExpander $type_param->fq_classlike_name, $type_param->const_name, ReflectionProperty::IS_PRIVATE, + null, + [], + false, + $return_type instanceof TValueOf, ); } catch (CircularReferenceException $e) { return [$return_type]; @@ -1148,9 +1108,11 @@ class TypeExpander } else { $new_return_types = TValueOf::getValueType(new Union($type_atomics), $codebase); } + if ($new_return_types === null) { return [$return_type]; } + return array_values($new_return_types->getAtomicTypes()); } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeParser.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeParser.php index fc0016f7..35ca41aa 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeParser.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeParser.php @@ -31,6 +31,7 @@ use Psalm\Type\Atomic\TArray; use Psalm\Type\Atomic\TArrayKey; use Psalm\Type\Atomic\TCallable; use Psalm\Type\Atomic\TCallableKeyedArray; +use Psalm\Type\Atomic\TCallableObject; use Psalm\Type\Atomic\TClassConstant; use Psalm\Type\Atomic\TClassString; use Psalm\Type\Atomic\TClassStringMap; @@ -61,6 +62,7 @@ use Psalm\Type\Atomic\TTemplateParamClass; use Psalm\Type\Atomic\TTemplatePropertiesOf; use Psalm\Type\Atomic\TTemplateValueOf; use Psalm\Type\Atomic\TTypeAlias; +use Psalm\Type\Atomic\TUnknownClassString; use Psalm\Type\Atomic\TValueOf; use Psalm\Type\TypeNode; use Psalm\Type\Union; @@ -69,6 +71,7 @@ use function array_key_exists; use function array_key_first; use function array_keys; use function array_map; +use function array_merge; use function array_pop; use function array_shift; use function array_unique; @@ -91,6 +94,7 @@ use function stripslashes; use function strlen; use function strpos; use function strtolower; +use function strtr; use function substr; /** @@ -420,8 +424,8 @@ class TypeParser return new TLiteralFloat((float) $parse_tree->value, $from_docblock); } - if (preg_match('/^\-?(0|[1-9][0-9]*)$/', $parse_tree->value)) { - return new TLiteralInt((int) $parse_tree->value, $from_docblock); + if (preg_match('/^\-?(0|[1-9]([0-9_]*[0-9])?)$/', $parse_tree->value)) { + return new TLiteralInt((int) strtr($parse_tree->value, ['_' => '']), $from_docblock); } if (!preg_match('@^(\$this|\\\\?[a-zA-Z_\x7f-\xff][\\\\\-0-9a-zA-Z_\x7f-\xff]*)$@', $parse_tree->value)) { @@ -684,6 +688,9 @@ class TypeParser } if ($generic_type_value === 'list') { + if (count($generic_params) > 1) { + throw new TypeParseTreeException('Too many template parameters for list'); + } return Type::getListAtomic($generic_params[0], $from_docblock); } @@ -710,13 +717,25 @@ class TypeParser $types = []; foreach ($generic_params[0]->getAtomicTypes() as $type) { - if (!$type instanceof TNamedObject) { - throw new TypeParseTreeException('Class string param should be a named object'); + if ($type instanceof TNamedObject) { + $types[] = new TClassString($type->value, $type, false, false, false, $from_docblock); + continue; } - $types[] = new TClassString($type->value, $type, false, false, false, $from_docblock); + if ($type instanceof TCallableObject) { + $types[] = new TUnknownClassString($type, false, $from_docblock); + continue; + } + + throw new TypeParseTreeException('class-string param can only target to named or callable objects'); } + assert( + $types !== [], + 'Since `Union` cannot be empty and all non-supported atomics lead to thrown exception,' + .' we can safely assert that the types array is non-empty.', + ); + return new Union($types); } @@ -778,7 +797,7 @@ class TypeParser if ($template_param->getIntersectionTypes()) { throw new TypeParseTreeException( $generic_type_value . '<' . $param_name . '> must be a TTemplateParam' - . ' with no intersection types.', + . ' with no intersection types.', ); } @@ -1093,6 +1112,10 @@ class TypeParser $intersection_types[$name] = $atomic_type; } + if ($intersection_types === []) { + return new TMixed(); + } + $first_type = reset($intersection_types); $last_type = end($intersection_types); @@ -1112,129 +1135,64 @@ class TypeParser } if ($onlyTKeyedArray) { - /** @var non-empty-array */ - $properties = []; - - if ($first_type instanceof TArray) { - array_shift($intersection_types); - } elseif ($last_type instanceof TArray) { - array_pop($intersection_types); - } - - $all_sealed = true; - - /** @var TKeyedArray $intersection_type */ - foreach ($intersection_types as $intersection_type) { - foreach ($intersection_type->properties as $property => $property_type) { - if ($intersection_type->fallback_params !== null) { - $all_sealed = false; - } - - if (!array_key_exists($property, $properties)) { - $properties[$property] = $property_type; - continue; - } - - $new_type = Type::intersectUnionTypes( - $properties[$property], - $property_type, - $codebase, - ); - - if ($new_type === null) { - throw new TypeParseTreeException( - 'Incompatible intersection types for "' . $property . '", ' - . $properties[$property] . ' and ' . $property_type - . ' provided', - ); - } - $properties[$property] = $new_type; - } - } - - $first_or_last_type = $first_type instanceof TArray - ? $first_type - : ($last_type instanceof TArray ? $last_type : null); - - $fallback_params = null; - - if ($first_or_last_type !== null) { - $fallback_params = [ - $first_or_last_type->type_params[0], - $first_or_last_type->type_params[1], - ]; - } elseif (!$all_sealed) { - $fallback_params = [Type::getArrayKey(), Type::getMixed()]; - } - - return new TKeyedArray( - $properties, - null, - $fallback_params, - false, + /** + * @var array $intersection_types + * @var TKeyedArray $first_type + * @var TKeyedArray $last_type + */ + return self::getTypeFromKeyedArrays( + $codebase, + $intersection_types, + $first_type, + $last_type, $from_docblock, ); } - $keyed_intersection_types = []; + $keyed_intersection_types = self::extractKeyedIntersectionTypes( + $codebase, + $intersection_types, + ); - if ($intersection_types[0] instanceof TTypeAlias) { - foreach ($intersection_types as $intersection_type) { - if (!$intersection_type instanceof TTypeAlias) { - throw new TypeParseTreeException( - 'Intersection types with a type alias can only be comprised of other type aliases, ' - . get_class($intersection_type) . ' provided', - ); - } + $intersect_static = false; - $keyed_intersection_types[$intersection_type->getKey()] = $intersection_type; - } + if (isset($keyed_intersection_types['static'])) { + unset($keyed_intersection_types['static']); + $intersect_static = true; + } - $first_type = array_shift($keyed_intersection_types); + if ($keyed_intersection_types === [] && $intersect_static) { + return new TNamedObject('static', false, false, [], $from_docblock); + } - if ($keyed_intersection_types) { - return $first_type->setIntersectionTypes($keyed_intersection_types); - } - } else { - foreach ($intersection_types as $intersection_type) { - if (!$intersection_type instanceof TIterable - && !$intersection_type instanceof TNamedObject - && !$intersection_type instanceof TTemplateParam - && !$intersection_type instanceof TObjectWithProperties - ) { - throw new TypeParseTreeException( - 'Intersection types must be all objects, ' - . get_class($intersection_type) . ' provided', - ); - } + $first_type = array_shift($keyed_intersection_types); - $keyed_intersection_types[$intersection_type instanceof TIterable - ? $intersection_type->getId() - : $intersection_type->getKey()] = $intersection_type; - } + // Keyed array intersection are merged together and are not combinable with object-types + if ($first_type instanceof TKeyedArray) { + // assume all types are keyed arrays + array_unshift($keyed_intersection_types, $first_type); + /** @var TKeyedArray $last_type */ + $last_type = end($keyed_intersection_types); - $intersect_static = false; + /** @var array $keyed_intersection_types */ + return self::getTypeFromKeyedArrays( + $codebase, + $keyed_intersection_types, + $first_type, + $last_type, + $from_docblock, + ); + } - if (isset($keyed_intersection_types['static'])) { - unset($keyed_intersection_types['static']); - $intersect_static = true; - } + if ($intersect_static + && $first_type instanceof TNamedObject + ) { + $first_type->is_static = true; + } - if (!$keyed_intersection_types && $intersect_static) { - return new TNamedObject('static', false, false, [], $from_docblock); - } - - $first_type = array_shift($keyed_intersection_types); - - if ($intersect_static - && $first_type instanceof TNamedObject - ) { - $first_type->is_static = true; - } - - if ($keyed_intersection_types) { - return $first_type->setIntersectionTypes($keyed_intersection_types); - } + if ($keyed_intersection_types) { + /** @var non-empty-array $keyed_intersection_types */ + return $first_type->setIntersectionTypes($keyed_intersection_types); } return $first_type; @@ -1397,6 +1355,16 @@ class TypeParser $sealed = true; + $extra_params = null; + + $last_property_branch = end($parse_tree->children); + if ($last_property_branch instanceof GenericTree + && $last_property_branch->value === '' + ) { + $extra_params = $last_property_branch->children; + array_pop($parse_tree->children); + } + foreach ($parse_tree->children as $i => $property_branch) { $class_string = false; @@ -1517,14 +1485,249 @@ class TypeParser return new TArray([Type::getNever($from_docblock), Type::getNever($from_docblock)], $from_docblock); } + if ($extra_params) { + if ($is_list && count($extra_params) !== 1) { + throw new TypeParseTreeException('Must have exactly one extra field!'); + } + if (!$is_list && count($extra_params) !== 2) { + throw new TypeParseTreeException('Must have exactly two extra fields!'); + } + $final_extra_params = $is_list ? [Type::getListKey(true)] : []; + foreach ($extra_params as $child_tree) { + $child_type = self::getTypeFromTree( + $child_tree, + $codebase, + null, + $template_type_map, + $type_aliases, + $from_docblock, + ); + if ($child_type instanceof Atomic) { + $child_type = new Union([$child_type]); + } + $final_extra_params []= $child_type; + } + $extra_params = $final_extra_params; + } return new $class( $properties, $class_strings, - $sealed + $extra_params ?? ($sealed ? null - : [$is_list ? Type::getListKey() : Type::getArrayKey(), Type::getMixed()], + : [$is_list ? Type::getListKey() : Type::getArrayKey(), Type::getMixed()] + ), $is_list, $from_docblock, ); } + + /** + * @param TNamedObject|TObjectWithProperties|TCallableObject|TIterable|TTemplateParam|TKeyedArray $intersection_type + */ + private static function extractIntersectionKey(Atomic $intersection_type): string + { + return $intersection_type instanceof TIterable || $intersection_type instanceof TKeyedArray + ? $intersection_type->getId() + : $intersection_type->getKey(); + } + + /** + * @param non-empty-array $intersection_types + * @return non-empty-array + */ + private static function extractKeyedIntersectionTypes( + Codebase $codebase, + array $intersection_types + ): array { + $keyed_intersection_types = []; + $callable_intersection = null; + $any_object_type_found = $any_array_found = false; + + $normalized_intersection_types = self::resolveTypeAliases( + $codebase, + $intersection_types, + ); + + foreach ($normalized_intersection_types as $intersection_type) { + if ($intersection_type instanceof TKeyedArray + && !$intersection_type instanceof TCallableKeyedArray + ) { + $any_array_found = true; + + if ($any_object_type_found) { + throw new TypeParseTreeException( + 'The intersection type must not mix array and object types!', + ); + } + + $keyed_intersection_types[self::extractIntersectionKey($intersection_type)] = $intersection_type; + continue; + } + + $any_object_type_found = true; + + if ($intersection_type instanceof TIterable + || $intersection_type instanceof TNamedObject + || $intersection_type instanceof TTemplateParam + || $intersection_type instanceof TObjectWithProperties + ) { + $keyed_intersection_types[self::extractIntersectionKey($intersection_type)] = $intersection_type; + continue; + } + + if (get_class($intersection_type) === TObject::class) { + continue; + } + + if ($intersection_type instanceof TCallable) { + if ($callable_intersection !== null) { + throw new TypeParseTreeException( + 'The intersection type must not contain more than one callable type!', + ); + } + $callable_intersection = $intersection_type; + continue; + } + + throw new TypeParseTreeException( + 'Intersection types must be all objects, ' + . get_class($intersection_type) . ' provided', + ); + } + + if ($callable_intersection !== null) { + $callable_object_type = new TCallableObject( + $callable_intersection->from_docblock, + $callable_intersection, + ); + + $keyed_intersection_types[self::extractIntersectionKey($callable_object_type)] = $callable_object_type; + } + + if ($any_object_type_found && $any_array_found) { + throw new TypeParseTreeException( + 'Intersection types must be all objects or all keyed array.', + ); + } + + assert($keyed_intersection_types !== []); + + return $keyed_intersection_types; + } + + /** + * @param array $intersection_types + * @return array + */ + private static function resolveTypeAliases(Codebase $codebase, array $intersection_types): array + { + $normalized_intersection_types = []; + $modified = false; + foreach ($intersection_types as $intersection_type) { + if (!$intersection_type instanceof TTypeAlias) { + $normalized_intersection_types[] = [$intersection_type]; + continue; + } + + $modified = true; + + $normalized_intersection_types[] = TypeExpander::expandAtomic( + $codebase, + $intersection_type, + null, + null, + null, + true, + false, + false, + true, + true, + true, + ); + } + + if ($modified === false) { + return $intersection_types; + } + + return self::resolveTypeAliases( + $codebase, + array_merge(...$normalized_intersection_types), + ); + } + + /** + * @param array $intersection_types + * @param TKeyedArray|TArray $first_type + * @param TKeyedArray|TArray $last_type + */ + private static function getTypeFromKeyedArrays( + Codebase $codebase, + array $intersection_types, + Atomic $first_type, + Atomic $last_type, + bool $from_docblock + ): Atomic { + /** @var non-empty-array */ + $properties = []; + + if ($first_type instanceof TArray) { + array_shift($intersection_types); + } elseif ($last_type instanceof TArray) { + array_pop($intersection_types); + } + + $all_sealed = true; + + foreach ($intersection_types as $intersection_type) { + if ($intersection_type->fallback_params !== null) { + $all_sealed = false; + } + + foreach ($intersection_type->properties as $property => $property_type) { + if (!array_key_exists($property, $properties)) { + $properties[$property] = $property_type; + continue; + } + + $new_type = Type::intersectUnionTypes( + $properties[$property], + $property_type, + $codebase, + ); + + if ($new_type === null) { + throw new TypeParseTreeException( + 'Incompatible intersection types for "' . $property . '", ' + . $properties[$property] . ' and ' . $property_type + . ' provided', + ); + } + $properties[$property] = $new_type; + } + } + + $first_or_last_type = $first_type instanceof TArray + ? $first_type + : ($last_type instanceof TArray ? $last_type : null); + + $fallback_params = null; + + if ($first_or_last_type !== null) { + $fallback_params = [ + $first_or_last_type->type_params[0], + $first_or_last_type->type_params[1], + ]; + } elseif (!$all_sealed) { + $fallback_params = [Type::getArrayKey(), Type::getMixed()]; + } + + return new TKeyedArray( + $properties, + null, + $fallback_params, + false, + $from_docblock, + ); + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeTokenizer.php b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeTokenizer.php index ca7f1034..66e463e4 100644 --- a/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeTokenizer.php +++ b/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeTokenizer.php @@ -41,6 +41,7 @@ class TypeTokenizer 'non-empty-array' => true, 'non-empty-string' => true, 'non-falsy-string' => true, + 'truthy-string' => true, 'iterable' => true, 'null' => true, 'mixed' => true, @@ -107,7 +108,6 @@ class TypeTokenizer * contains the string token and the second element contains its offset, * * @return list - * @psalm-suppress PossiblyUndefinedIntArrayOffset */ public static function tokenize(string $string_type, bool $ignore_space = true): array { diff --git a/vendor/vimeo/psalm/src/Psalm/Issue/InheritorViolation.php b/vendor/vimeo/psalm/src/Psalm/Issue/InheritorViolation.php new file mode 100644 index 00000000..8e0a7a08 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Issue/InheritorViolation.php @@ -0,0 +1,9 @@ + 0) { if ($issue_baseline[$file][$type]['o'] === count($issue_baseline[$file][$type]['s'])) { $position = array_search( - trim($issue_data->selected_text), + str_replace("\r\n", "\n", trim($issue_data->selected_text)), $issue_baseline[$file][$type]['s'], true, ); diff --git a/vendor/vimeo/psalm/src/Psalm/Plugin/EventHandler/BeforeExpressionAnalysisInterface.php b/vendor/vimeo/psalm/src/Psalm/Plugin/EventHandler/BeforeExpressionAnalysisInterface.php new file mode 100644 index 00000000..60d9f47a --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Plugin/EventHandler/BeforeExpressionAnalysisInterface.php @@ -0,0 +1,15 @@ + + */ + private array $file_replacements; + + /** + * Called before an expression is checked + * + * @param list $file_replacements + * @internal + */ + public function __construct( + Expr $expr, + Context $context, + StatementsSource $statements_source, + Codebase $codebase, + array $file_replacements = [] + ) { + $this->expr = $expr; + $this->context = $context; + $this->statements_source = $statements_source; + $this->codebase = $codebase; + $this->file_replacements = $file_replacements; + } + + public function getExpr(): Expr + { + return $this->expr; + } + + public function getContext(): Context + { + return $this->context; + } + + public function getStatementsSource(): StatementsSource + { + return $this->statements_source; + } + + public function getCodebase(): Codebase + { + return $this->codebase; + } + + /** + * @return list + */ + public function getFileReplacements(): array + { + return $this->file_replacements; + } + + /** + * @param list $file_replacements + */ + public function setFileReplacements(array $file_replacements): void + { + $this->file_replacements = $file_replacements; + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Storage/ClassConstantStorage.php b/vendor/vimeo/psalm/src/Psalm/Storage/ClassConstantStorage.php index 66917f81..9c6d7cfc 100644 --- a/vendor/vimeo/psalm/src/Psalm/Storage/ClassConstantStorage.php +++ b/vendor/vimeo/psalm/src/Psalm/Storage/ClassConstantStorage.php @@ -7,6 +7,9 @@ use Psalm\Internal\Analyzer\ClassLikeAnalyzer; use Psalm\Internal\Scanner\UnresolvedConstantComponent; use Psalm\Type\Union; +use function array_values; +use function property_exists; + /** * @psalm-suppress PossiblyUnusedProperty * @psalm-immutable @@ -88,4 +91,36 @@ final class ClassConstantStorage $this->suppressed_issues = $suppressed_issues; $this->description = $description; } + + /** + * Used in the Language Server + */ + public function getHoverMarkdown(string $const): string + { + switch ($this->visibility) { + case ClassLikeAnalyzer::VISIBILITY_PRIVATE: + $visibility_text = 'private'; + break; + + case ClassLikeAnalyzer::VISIBILITY_PROTECTED: + $visibility_text = 'protected'; + break; + + default: + $visibility_text = 'public'; + } + + $value = ''; + if ($this->type) { + $types = $this->type->getAtomicTypes(); + $type = array_values($types)[0]; + if (property_exists($type, 'value')) { + /** @psalm-suppress UndefinedPropertyFetch */ + $value = " = {$type->value};"; + } + } + + + return "$visibility_text const $const$value"; + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Storage/ClassLikeStorage.php b/vendor/vimeo/psalm/src/Psalm/Storage/ClassLikeStorage.php index 45fa635d..5be0d522 100644 --- a/vendor/vimeo/psalm/src/Psalm/Storage/ClassLikeStorage.php +++ b/vendor/vimeo/psalm/src/Psalm/Storage/ClassLikeStorage.php @@ -4,6 +4,8 @@ namespace Psalm\Storage; use Psalm\Aliases; use Psalm\CodeLocation; +use Psalm\Codebase; +use Psalm\Config; use Psalm\Internal\Analyzer\ClassLikeAnalyzer; use Psalm\Internal\MethodIdentifier; use Psalm\Internal\Type\TypeAlias\ClassTypeAlias; @@ -66,14 +68,14 @@ final class ClassLikeStorage implements HasAttributesInterface public $mixin_declaring_fqcln; /** - * @var bool + * @var ?bool */ - public $sealed_properties = false; + public $sealed_properties = null; /** - * @var bool + * @var ?bool */ - public $sealed_methods = false; + public $sealed_methods = null; /** * @var bool @@ -313,6 +315,11 @@ final class ClassLikeStorage implements HasAttributesInterface */ public $appearing_property_ids = []; + /** + * @var ?Union + */ + public $inheritors = null; + /** * @var array */ @@ -485,6 +492,24 @@ final class ClassLikeStorage implements HasAttributesInterface return $this->attributes; } + public function hasAttributeIncludingParents( + string $fq_class_name, + Codebase $codebase + ): bool { + if ($this->hasAttribute($fq_class_name)) { + return true; + } + + foreach ($this->parent_classes as $parent_class) { + $parent_class_storage = $codebase->classlike_storage_provider->get($parent_class); + if ($parent_class_storage->hasAttribute($fq_class_name)) { + return true; + } + } + + return false; + } + /** * Get the template constraint types for the class. * @@ -500,4 +525,25 @@ final class ClassLikeStorage implements HasAttributesInterface return $type_params; } + + public function hasSealedProperties(Config $config): bool + { + return $this->sealed_properties ?? $config->seal_all_properties; + } + + public function hasSealedMethods(Config $config): bool + { + return $this->sealed_methods ?? $config->seal_all_methods; + } + + private function hasAttribute(string $fq_class_name): bool + { + foreach ($this->attributes as $attribute) { + if ($fq_class_name === $attribute->fq_class_name) { + return true; + } + } + + return false; + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Storage/FunctionLikeStorage.php b/vendor/vimeo/psalm/src/Psalm/Storage/FunctionLikeStorage.php index 63f3c895..929e2b84 100644 --- a/vendor/vimeo/psalm/src/Psalm/Storage/FunctionLikeStorage.php +++ b/vendor/vimeo/psalm/src/Psalm/Storage/FunctionLikeStorage.php @@ -10,6 +10,7 @@ use Psalm\Type\Union; use function array_column; use function array_fill_keys; use function array_map; +use function count; use function implode; abstract class FunctionLikeStorage implements HasAttributesInterface @@ -245,30 +246,53 @@ abstract class FunctionLikeStorage implements HasAttributesInterface public bool $public_api = false; - public function __toString(): string + /** + * Used in the Language Server + */ + public function getHoverMarkdown(): string { - return $this->getSignature(false); + $params = count($this->params) > 0 ? "\n" . implode( + ",\n", + array_map( + function (FunctionLikeParameter $param): string { + $realType = $param->type ?: 'mixed'; + return " {$realType} \${$param->name}"; + }, + $this->params, + ), + ) . "\n" : ''; + $return_type = $this->return_type ?: 'mixed'; + $symbol_text = "function {$this->cased_name}({$params}): {$return_type}"; + + if (!$this instanceof MethodStorage) { + return $symbol_text; + } + + switch ($this->visibility) { + case ClassLikeAnalyzer::VISIBILITY_PRIVATE: + $visibility_text = 'private'; + break; + + case ClassLikeAnalyzer::VISIBILITY_PROTECTED: + $visibility_text = 'protected'; + break; + + default: + $visibility_text = 'public'; + } + + return $visibility_text . ' ' . $symbol_text; } - public function getSignature(bool $allow_newlines): string + public function getCompletionSignature(): string { - $newlines = $allow_newlines && !empty($this->params); - - $symbol_text = 'function ' . $this->cased_name . '(' - . ($newlines ? "\n" : '') - . implode( - ',' . ($newlines ? "\n" : ' '), - array_map( - static fn(FunctionLikeParameter $param): string => - ($newlines ? ' ' : '') - . ($param->type ? $param->type->getId(false) : 'mixed') - . ' $' . $param->name, - $this->params, - ), - ) - . ($newlines ? "\n" : '') - . ') : ' - . ($this->return_type ?: 'mixed'); + $symbol_text = 'function ' . $this->cased_name . '(' . implode( + ',', + array_map( + fn(FunctionLikeParameter $param): string => ($param->type ?: 'mixed') . ' $' . $param->name, + $this->params, + ), + ) . ') : ' . ($this->return_type ?: 'mixed'); if (!$this instanceof MethodStorage) { return $symbol_text; @@ -317,4 +341,18 @@ abstract class FunctionLikeStorage implements HasAttributesInterface { return $this->attributes; } + + public function __toString(): string + { + return $this->getCompletionSignature(); + } + + /** + * @deprecated will be removed in Psalm 6. use {@see FunctionLikeStorage::getCompletionSignature()} instead + * @psalm-suppress PossiblyUnusedParam, PossiblyUnusedMethod + */ + public function getSignature(bool $allow_newlines): string + { + return $this->getCompletionSignature(); + } } diff --git a/vendor/vimeo/psalm/src/Psalm/Type.php b/vendor/vimeo/psalm/src/Psalm/Type.php index 4a066707..3b98f05c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type.php +++ b/vendor/vimeo/psalm/src/Psalm/Type.php @@ -15,6 +15,7 @@ use Psalm\Type\Atomic; use Psalm\Type\Atomic\TArray; use Psalm\Type\Atomic\TArrayKey; use Psalm\Type\Atomic\TBool; +use Psalm\Type\Atomic\TCallableObject; use Psalm\Type\Atomic\TClassString; use Psalm\Type\Atomic\TClosure; use Psalm\Type\Atomic\TFalse; @@ -483,12 +484,17 @@ abstract class Type } private static ?Union $listKey = null; + private static ?Union $listKeyFromDocblock = null; /** * @psalm-pure + * @psalm-suppress ImpureStaticProperty Used for caching */ - public static function getListKey(): Union + public static function getListKey(bool $from_docblock = false): Union { + if ($from_docblock) { + return self::$listKeyFromDocblock ??= new Union([new TIntRange(0, null, true)]); + } return self::$listKey ??= new Union([new TIntRange(0, null)]); } @@ -962,10 +968,18 @@ abstract class Type private static function hasIntersection(Atomic $type): bool { - return ($type instanceof TIterable - || $type instanceof TNamedObject - || $type instanceof TTemplateParam - || $type instanceof TObjectWithProperties - ) && $type->extra_types; + return self::isIntersectionType($type) && $type->extra_types; + } + + /** + * @psalm-assert-if-true TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $type + */ + public static function isIntersectionType(Atomic $type): bool + { + return $type instanceof TNamedObject + || $type instanceof TTemplateParam + || $type instanceof TIterable + || $type instanceof TObjectWithProperties + || $type instanceof TCallableObject; } } diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/CallableTrait.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/CallableTrait.php index 90f70aad..4ca12639 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/CallableTrait.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/CallableTrait.php @@ -38,6 +38,7 @@ trait CallableTrait * Constructs a new instance of a generic type * * @param list $params + * @deprecated */ public function __construct( string $value = 'callable', @@ -77,11 +78,10 @@ trait CallableTrait $cloned->is_pure = $is_pure; return $cloned; } - public function getKey(bool $include_extra = true): string + + public function getParamString(): string { $param_string = ''; - $return_type_string = ''; - if ($this->params !== null) { $param_string .= '('; foreach ($this->params as $i => $param) { @@ -95,12 +95,27 @@ trait CallableTrait $param_string .= ')'; } + return $param_string; + } + + public function getReturnTypeString(): string + { + $return_type_string = ''; + if ($this->return_type !== null) { $return_type_multiple = count($this->return_type->getAtomicTypes()) > 1; $return_type_string = ':' . ($return_type_multiple ? '(' : '') . $this->return_type->getId() . ($return_type_multiple ? ')' : ''); } + return $return_type_string; + } + + public function getKey(bool $include_extra = true): string + { + $param_string = $this->getParamString(); + $return_type_string = $this->getReturnTypeString(); + return ($this->is_pure ? 'pure-' : ($this->is_pure === null ? '' : 'impure-')) . $this->value . $param_string . $return_type_string; } diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/HasIntersectionTrait.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/HasIntersectionTrait.php index c5a88d55..9a8bc286 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/HasIntersectionTrait.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/HasIntersectionTrait.php @@ -18,7 +18,7 @@ use function implode; trait HasIntersectionTrait { /** - * @var array + * @var array */ public array $extra_types = []; @@ -39,7 +39,7 @@ trait HasIntersectionTrait '&', array_map( /** - * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties $extra_type + * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $extra_type */ static fn(Atomic $extra_type): string => $extra_type->toNamespacedString( $namespace, @@ -53,7 +53,7 @@ trait HasIntersectionTrait } /** - * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties $type + * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $type * @return static */ public function addIntersectionType(Atomic $type): self @@ -65,7 +65,7 @@ trait HasIntersectionTrait } /** - * @param array $types + * @param array $types * @return static */ public function setIntersectionTypes(array $types): self @@ -79,7 +79,7 @@ trait HasIntersectionTrait } /** - * @return array + * @return array */ public function getIntersectionTypes(): array { @@ -87,7 +87,7 @@ trait HasIntersectionTrait } /** - * @return array|null + * @return array|null */ protected function replaceIntersectionTemplateTypesWithArgTypes( TemplateResult $template_result, @@ -125,7 +125,7 @@ trait HasIntersectionTrait } /** - * @return array|null + * @return array|null */ protected function replaceIntersectionTemplateTypesWithStandins( TemplateResult $template_result, diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TArray.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TArray.php index b3941efb..06477607 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TArray.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TArray.php @@ -41,7 +41,7 @@ class TArray extends Atomic public function __construct(array $type_params, bool $from_docblock = false) { $this->type_params = $type_params; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallable.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallable.php index 7266f17e..7ef847d4 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallable.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallable.php @@ -5,7 +5,9 @@ namespace Psalm\Type\Atomic; use Psalm\Codebase; use Psalm\Internal\Analyzer\StatementsAnalyzer; use Psalm\Internal\Type\TemplateResult; +use Psalm\Storage\FunctionLikeParameter; use Psalm\Type\Atomic; +use Psalm\Type\Union; /** * Denotes the `callable` type. Can result from an `is_callable` check. @@ -21,6 +23,25 @@ final class TCallable extends Atomic */ public $value; + /** + * Constructs a new instance of a generic type + * + * @param list $params + */ + public function __construct( + string $value = 'callable', + ?array $params = null, + ?Union $return_type = null, + ?bool $is_pure = null, + bool $from_docblock = false + ) { + $this->value = $value; + $this->params = $params; + $this->return_type = $return_type; + $this->is_pure = $is_pure; + parent::__construct($from_docblock); + } + /** * @param array $aliased_classes */ diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallableObject.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallableObject.php index db998562..3287617e 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallableObject.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TCallableObject.php @@ -9,9 +9,24 @@ namespace Psalm\Type\Atomic; */ final class TCallableObject extends TObject { + use HasIntersectionTrait; + + public ?TCallable $callable; + + public function __construct(bool $from_docblock = false, ?TCallable $callable = null) + { + parent::__construct($from_docblock); + $this->callable = $callable; + } + public function getKey(bool $include_extra = true): string { - return 'callable-object'; + $key = 'callable-object'; + if ($this->callable !== null) { + $key .= $this->callable->getParamString() . $this->callable->getReturnTypeString(); + } + + return $key; } /** diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassConstant.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassConstant.php index db10f48b..d0e14c11 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassConstant.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassConstant.php @@ -22,7 +22,7 @@ final class TClassConstant extends Atomic { $this->fq_classlike_name = $fq_classlike_name; $this->const_name = $const_name; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassString.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassString.php index ff611d08..723f8f40 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassString.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassString.php @@ -54,7 +54,7 @@ class TClassString extends TString $this->is_loaded = $is_loaded; $this->is_interface = $is_interface; $this->is_enum = $is_enum; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } /** * @return static diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassStringMap.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassStringMap.php index 9cd25109..d15d297f 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassStringMap.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClassStringMap.php @@ -46,7 +46,7 @@ final class TClassStringMap extends Atomic $this->param_name = $param_name; $this->as_type = $as_type; $this->value_param = $value_param; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getId(bool $exact = true, bool $nested = false): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClosure.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClosure.php index 3ccabeeb..97949adc 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClosure.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TClosure.php @@ -26,7 +26,7 @@ final class TClosure extends TNamedObject /** * @param list $params * @param array $byref_uses - * @param array $extra_types + * @param array $extra_types */ public function __construct( string $value = 'callable', @@ -37,13 +37,17 @@ final class TClosure extends TNamedObject array $extra_types = [], bool $from_docblock = false ) { - $this->value = $value; $this->params = $params; $this->return_type = $return_type; $this->is_pure = $is_pure; $this->byref_uses = $byref_uses; - $this->extra_types = $extra_types; - $this->from_docblock = $from_docblock; + parent::__construct( + $value, + false, + false, + $extra_types, + $from_docblock, + ); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id): bool diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TConditional.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TConditional.php index 84e0747b..9d3bbc92 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TConditional.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TConditional.php @@ -60,7 +60,7 @@ final class TConditional extends Atomic $this->conditional_type = $conditional_type; $this->if_type = $if_type; $this->else_type = $else_type; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function setTypes( diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetClass.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetClass.php index 61ebc89a..168355da 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetClass.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetClass.php @@ -30,6 +30,7 @@ final class TDependentGetClass extends TString implements DependentType { $this->typeof = $typeof; $this->as_type = $as_type; + parent::__construct(false); } public function getId(bool $exact = true, bool $nested = false): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetDebugType.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetDebugType.php index 8f33a19c..c71b9b71 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetDebugType.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetDebugType.php @@ -22,6 +22,7 @@ final class TDependentGetDebugType extends TString implements DependentType public function __construct(string $typeof) { $this->typeof = $typeof; + parent::__construct(false); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetType.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetType.php index abec9425..ca1c4f08 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetType.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentGetType.php @@ -22,6 +22,7 @@ final class TDependentGetType extends TString public function __construct(string $typeof) { $this->typeof = $typeof; + parent::__construct(false); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id): bool diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentListKey.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentListKey.php index 62cf48d2..042c95d4 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentListKey.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TDependentListKey.php @@ -23,6 +23,7 @@ final class TDependentListKey extends TInt implements DependentType public function __construct(string $var_id) { $this->var_id = $var_id; + parent::__construct(false); } public function getId(bool $exact = true, bool $nested = false): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TGenericObject.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TGenericObject.php index 388ed91a..45aa50b8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TGenericObject.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TGenericObject.php @@ -37,7 +37,7 @@ final class TGenericObject extends TNamedObject /** * @param string $value the name of the object * @param non-empty-list $type_params - * @param array $extra_types + * @param array $extra_types */ public function __construct( string $value, @@ -51,12 +51,15 @@ final class TGenericObject extends TNamedObject $value = substr($value, 1); } - $this->value = $value; $this->type_params = $type_params; $this->remapped_params = $remapped_params; - $this->is_static = $is_static; - $this->extra_types = $extra_types; - $this->from_docblock = $from_docblock; + parent::__construct( + $value, + $is_static, + false, + $extra_types, + $from_docblock, + ); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntMask.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntMask.php index 09a2e83c..e6e57539 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntMask.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntMask.php @@ -19,7 +19,7 @@ final class TIntMask extends TInt public function __construct(array $values, bool $from_docblock = false) { $this->values = $values; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntMaskOf.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntMaskOf.php index 0048ee6f..d5a4ae79 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntMaskOf.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntMaskOf.php @@ -22,7 +22,7 @@ final class TIntMaskOf extends TInt public function __construct(Atomic $value, bool $from_docblock = false) { $this->value = $value; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntRange.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntRange.php index ad255472..dd0c9fa8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntRange.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIntRange.php @@ -35,8 +35,8 @@ final class TIntRange extends TInt ) { $this->min_bound = $min_bound; $this->max_bound = $max_bound; - $this->from_docblock = $from_docblock; $this->dependent_list_key = $dependent_list_key; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIterable.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIterable.php index da9fce58..6b6c9ea3 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIterable.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TIterable.php @@ -43,7 +43,7 @@ final class TIterable extends Atomic /** * @param array{Union, Union}|array $type_params - * @param array $extra_types + * @param array $extra_types */ public function __construct(array $type_params = [], array $extra_types = [], bool $from_docblock = false) { @@ -54,7 +54,7 @@ final class TIterable extends Atomic $this->type_params = [Type::getMixed(), Type::getMixed()]; } $this->extra_types = $extra_types; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyOf.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyOf.php index 56fdf8f9..09762e73 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyOf.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyOf.php @@ -21,7 +21,7 @@ final class TKeyOf extends TArrayKey public function __construct(Union $type, bool $from_docblock = false) { $this->type = $type; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyedArray.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyedArray.php index 45dfb6b2..8510b83d 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyedArray.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TKeyedArray.php @@ -10,10 +10,6 @@ use Psalm\Internal\Type\TemplateStandinTypeReplacer; use Psalm\Internal\Type\TypeCombiner; use Psalm\Type; use Psalm\Type\Atomic; -use Psalm\Type\Atomic\TArray; -use Psalm\Type\Atomic\TLiteralClassString; -use Psalm\Type\Atomic\TLiteralInt; -use Psalm\Type\Atomic\TNonEmptyArray; use Psalm\Type\Union; use UnexpectedValueException; @@ -49,7 +45,7 @@ class TKeyedArray extends Atomic /** * If the shape has fallback params then they are here * - * @var ?list{Union, Union} + * @var array{Union, Union}|null */ public $fallback_params; @@ -67,7 +63,7 @@ class TKeyedArray extends Atomic * Constructs a new instance of a generic type * * @param non-empty-array $properties - * @param ?list{Union, Union} $fallback_params + * @param array{Union, Union}|null $fallback_params * @param array $class_strings */ public function __construct( @@ -84,7 +80,6 @@ class TKeyedArray extends Atomic $this->class_strings = $class_strings; $this->fallback_params = $fallback_params; $this->is_list = $is_list; - $this->from_docblock = $from_docblock; if ($this->is_list) { $last_k = -1; $had_possibly_undefined = false; @@ -100,6 +95,7 @@ class TKeyedArray extends Atomic $last_k = $k; } } + parent::__construct($from_docblock); } /** @@ -144,15 +140,29 @@ class TKeyedArray extends Atomic return $cloned; } + public function isSealed(): bool + { + return $this->fallback_params === null; + } + + /** + * @psalm-assert-if-true list{Union} $this->properties + * @psalm-assert-if-true list{Union, Union} $this->fallback_params + */ + public function isGenericList(): bool + { + return $this->is_list + && count($this->properties) === 1 + && $this->fallback_params + && $this->properties[0]->equals($this->fallback_params[1], true, true, false); + } + public function getId(bool $exact = true, bool $nested = false): string { $property_strings = []; if ($this->is_list) { - if (count($this->properties) === 1 - && $this->fallback_params - && $this->properties[0]->equals($this->fallback_params[1], true, true, false) - ) { + if ($this->isGenericList()) { $t = $this->properties[0]->possibly_undefined ? 'list' : 'non-empty-list'; return "$t<".$this->fallback_params[1]->getId($exact).'>'; } @@ -192,8 +202,11 @@ class TKeyedArray extends Atomic } $params_part = $this->fallback_params !== null - ? ', ...<' . $this->fallback_params[0]->getId($exact) . ', ' - . $this->fallback_params[1]->getId($exact) . '>' + ? ', ...<' . ($this->is_list + ? $this->fallback_params[1]->getId($exact) + : $this->fallback_params[0]->getId($exact) . ', ' + . $this->fallback_params[1]->getId($exact) + ) . '>' : ''; return $key . '{' . implode(', ', $property_strings) . $params_part . '}'; @@ -410,7 +423,7 @@ class TKeyedArray extends Atomic public function isNonEmpty(): bool { - if ($this->is_list) { + if ($this->isGenericList()) { return !$this->properties[0]->possibly_undefined; } foreach ($this->properties as $property) { @@ -498,6 +511,35 @@ class TKeyedArray extends Atomic bool $add_lower_bound = false, int $depth = 0 ): self { + if ($input_type instanceof TKeyedArray + && $input_type->is_list + && $input_type->isSealed() + && $this->isGenericList() + ) { + $replaced_list_type = $this + ->getGenericArrayType() + ->replaceTemplateTypesWithStandins( + $template_result, + $codebase, + $statements_analyzer, + $input_type->getGenericArrayType(), + $input_arg_offset, + $calling_class, + $calling_function, + $replace, + $add_lower_bound, + $depth, + ) + ->type_params[1] + ->setPossiblyUndefined(!$this->isNonEmpty()); + + $cloned = clone $this; + $cloned->properties = [$replaced_list_type]; + $cloned->fallback_params = [$this->fallback_params[1], $replaced_list_type]; + + return $cloned; + } + $properties = $this->properties; foreach ($properties as $offset => $property) { @@ -663,8 +705,22 @@ class TKeyedArray extends Atomic */ private function escapeAndQuote($name) { - if (is_string($name) && ($name === '' || preg_match('/[^a-zA-Z0-9_]/', $name))) { - $name = '\'' . str_replace("\n", '\n', addslashes($name)) . '\''; + if (is_string($name)) { + $quote = false; + + if ($name === '' || preg_match('/[^a-zA-Z0-9_]/', $name)) { + $quote = true; + } + + if (preg_match('/^-?[1-9][0-9]*$/', $name) + && (string)(int) $name !== $name // overflow occured + ) { + $quote = true; + } + + if ($quote) { + $name = '\'' . str_replace("\n", '\n', addslashes($name)) . '\''; + } } return $name; diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TList.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TList.php index e21ca39c..9e2c611c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TList.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TList.php @@ -42,7 +42,7 @@ class TList extends Atomic public function __construct(Union $type_param, bool $from_docblock = false) { $this->type_param = $type_param; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } /** diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralFloat.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralFloat.php index 886c9152..c4e1a7fe 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralFloat.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralFloat.php @@ -15,7 +15,7 @@ final class TLiteralFloat extends TFloat public function __construct(float $value, bool $from_docblock = false) { $this->value = $value; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralInt.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralInt.php index b86495c6..8055974d 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralInt.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralInt.php @@ -15,7 +15,7 @@ final class TLiteralInt extends TInt public function __construct(int $value, bool $from_docblock = false) { $this->value = $value; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralString.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralString.php index 7346e5a0..6a622887 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralString.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TLiteralString.php @@ -42,7 +42,7 @@ class TLiteralString extends TString ); } $this->value = $value; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } /** diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TMixed.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TMixed.php index d122a432..02e3cc5b 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TMixed.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TMixed.php @@ -17,7 +17,7 @@ class TMixed extends Atomic public function __construct(bool $from_loop_isset = false, bool $from_docblock = false) { $this->from_loop_isset = $from_loop_isset; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNamedObject.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNamedObject.php index e26036ca..ee7c5d38 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNamedObject.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNamedObject.php @@ -46,7 +46,7 @@ class TNamedObject extends Atomic /** * @param string $value the name of the object - * @param array $extra_types + * @param array $extra_types */ public function __construct( string $value, @@ -63,7 +63,7 @@ class TNamedObject extends Atomic $this->is_static = $is_static; $this->definite_class = $definite_class; $this->extra_types = $extra_types; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } /** diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyArray.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyArray.php index f1031de0..4f967775 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyArray.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyArray.php @@ -39,11 +39,10 @@ class TNonEmptyArray extends TArray string $value = 'non-empty-array', bool $from_docblock = false ) { - $this->type_params = $type_params; $this->count = $count; $this->min_count = $min_count; $this->value = $value; - $this->from_docblock = $from_docblock; + parent::__construct($type_params, $from_docblock); } /** diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyList.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyList.php index 832363a6..e6c02940 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyList.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TNonEmptyList.php @@ -44,10 +44,10 @@ class TNonEmptyList extends TList ?int $min_count = null, bool $from_docblock = false ) { - $this->type_param = $type_param; $this->count = $count; $this->min_count = $min_count; - $this->from_docblock = $from_docblock; + /** @psalm-suppress DeprecatedClass */ + parent::__construct($type_param, $from_docblock); } public function getKeyedArray(): TKeyedArray diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TObjectWithProperties.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TObjectWithProperties.php index 1755d10b..cae5be7e 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TObjectWithProperties.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TObjectWithProperties.php @@ -42,7 +42,7 @@ final class TObjectWithProperties extends TObject * * @param array $properties * @param array $methods - * @param array $extra_types + * @param array $extra_types */ public function __construct( array $properties, @@ -53,10 +53,11 @@ final class TObjectWithProperties extends TObject $this->properties = $properties; $this->methods = $methods; $this->extra_types = $extra_types; - $this->from_docblock = $from_docblock; $this->is_stringable_object_only = $this->properties === [] && $this->methods === ['__tostring' => 'string']; + + parent::__construct($from_docblock); } /** @@ -234,7 +235,7 @@ final class TObjectWithProperties extends TObject foreach ($this->properties as $offset => $property) { $input_type_param = null; - if ($input_type instanceof TKeyedArray + if ($input_type instanceof TObjectWithProperties && isset($input_type->properties[$offset]) ) { $input_type_param = $input_type->properties[$offset]; diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TPropertiesOf.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TPropertiesOf.php index 425a477a..49da46df 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TPropertiesOf.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TPropertiesOf.php @@ -49,7 +49,7 @@ final class TPropertiesOf extends Atomic ) { $this->classlike_type = $classlike_type; $this->visibility_filter = $visibility_filter; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } /** diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TSingleLetter.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TSingleLetter.php index c12ad3d2..604e1ecb 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TSingleLetter.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TSingleLetter.php @@ -7,6 +7,6 @@ namespace Psalm\Type\Atomic; * * @psalm-immutable */ -final class TSingleLetter extends TString +final class TSingleLetter extends TNonEmptyString { } diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateIndexedAccess.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateIndexedAccess.php index 0ef28969..80c7db23 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateIndexedAccess.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateIndexedAccess.php @@ -33,7 +33,7 @@ final class TTemplateIndexedAccess extends Atomic $this->array_param_name = $array_param_name; $this->offset_param_name = $offset_param_name; $this->defining_class = $defining_class; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateKeyOf.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateKeyOf.php index 34bc1001..debb1fc8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateKeyOf.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateKeyOf.php @@ -39,7 +39,7 @@ final class TTemplateKeyOf extends Atomic $this->param_name = $param_name; $this->defining_class = $defining_class; $this->as = $as; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateParam.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateParam.php index 33af6d19..f1bb94b8 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateParam.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateParam.php @@ -48,7 +48,7 @@ final class TTemplateParam extends Atomic $this->as = $extends; $this->defining_class = $defining_class; $this->extra_types = $extra_types; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } /** diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateParamClass.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateParamClass.php index 900451eb..ccf40a27 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateParamClass.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateParamClass.php @@ -27,10 +27,15 @@ final class TTemplateParamClass extends TClassString bool $from_docblock = false ) { $this->param_name = $param_name; - $this->as = $as; - $this->as_type = $as_type; $this->defining_class = $defining_class; - $this->from_docblock = $from_docblock; + parent::__construct( + $as, + $as_type, + false, + false, + false, + $from_docblock, + ); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplatePropertiesOf.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplatePropertiesOf.php index e29e3710..9dbc710c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplatePropertiesOf.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplatePropertiesOf.php @@ -46,7 +46,7 @@ final class TTemplatePropertiesOf extends Atomic $this->defining_class = $defining_class; $this->as = $as; $this->visibility_filter = $visibility_filter; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateValueOf.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateValueOf.php index f8c29e58..6d00b32e 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateValueOf.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTemplateValueOf.php @@ -39,7 +39,7 @@ final class TTemplateValueOf extends Atomic $this->param_name = $param_name; $this->defining_class = $defining_class; $this->as = $as; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } public function getKey(bool $include_extra = true): string diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTypeAlias.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTypeAlias.php index 06ac86cf..e15c442c 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTypeAlias.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TTypeAlias.php @@ -14,6 +14,9 @@ final class TTypeAlias extends Atomic { /** * @var array|null + * @deprecated type aliases are resolved within {@see TypeParser::resolveTypeAliases()} and therefore the + * referencing type(s) are part of other intersection types. The intersection types are not set anymore + * and with v6 this property along with its related methods will get removed. */ public $extra_types; @@ -30,13 +33,19 @@ final class TTypeAlias extends Atomic { $this->declaring_fq_classlike_name = $declaring_fq_classlike_name; $this->alias_name = $alias_name; + /** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */ $this->extra_types = $extra_types; + parent::__construct(true); } /** * @param array|null $extra_types + * @deprecated type aliases are resolved within {@see TypeParser::resolveTypeAliases()} and therefore the + * referencing type(s) are part of other intersection types. This method will get removed with v6. + * @psalm-suppress PossiblyUnusedMethod For backwards compatibility, we have to keep this here. */ public function setIntersectionTypes(?array $extra_types): self { + /** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */ if ($extra_types === $this->extra_types) { return $this; } @@ -54,6 +63,7 @@ final class TTypeAlias extends Atomic public function getId(bool $exact = true, bool $nested = false): string { + /** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */ if ($this->extra_types) { return $this->getKey() . '&' . implode( '&', diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TUnknownClassString.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TUnknownClassString.php new file mode 100644 index 00000000..765b15e9 --- /dev/null +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TUnknownClassString.php @@ -0,0 +1,30 @@ +as_unknown_type = $as_unknown_type; + } +} diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TValueOf.php b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TValueOf.php index 34d28c92..9220c079 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TValueOf.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Atomic/TValueOf.php @@ -12,7 +12,6 @@ use Psalm\Type\Union; use function array_map; use function array_values; use function assert; -use function count; /** * Represents a value of an array or enum. @@ -27,9 +26,36 @@ final class TValueOf extends Atomic public function __construct(Union $type, bool $from_docblock = false) { $this->type = $type; - $this->from_docblock = $from_docblock; + parent::__construct($from_docblock); } + /** + * @param non-empty-array $cases + */ + private static function getValueTypeForNamedObject(array $cases, TNamedObject $atomic_type): Union + { + if ($atomic_type instanceof TEnumCase) { + assert(isset($cases[$atomic_type->case_name]), 'Should\'ve been verified in TValueOf#getValueType'); + $value = $cases[$atomic_type->case_name]->value; + assert($value !== null, 'Backed enum must have a value.'); + return new Union([ConstantTypeResolver::getLiteralTypeFromScalarValue($value)]); + } + + return new Union(array_map( + function (EnumCaseStorage $case): Atomic { + assert($case->value !== null); // Backed enum must have a value + return ConstantTypeResolver::getLiteralTypeFromScalarValue($case->value); + }, + array_values($cases), + )); + } + + protected function getChildNodeKeys(): array + { + return ['type']; + } + + public function getKey(bool $include_extra = true): string { return 'value-of<' . $this->type . '>'; @@ -107,19 +133,14 @@ final class TValueOf extends Atomic $cases = $class_storage->enum_cases; if (!$class_storage->is_enum || $class_storage->enum_type === null - || count($cases) === 0 + || $cases === [] + || ($atomic_type instanceof TEnumCase && !isset($cases[$atomic_type->case_name])) ) { // Invalid value-of, skip continue; } - $value_atomics = new Union(array_map( - function (EnumCaseStorage $case): Atomic { - assert($case->value !== null); // Backed enum must have a value - return ConstantTypeResolver::getLiteralTypeFromScalarValue($case->value); - }, - array_values($cases), - )); + $value_atomics = self::getValueTypeForNamedObject($cases, $atomic_type); } else { continue; } diff --git a/vendor/vimeo/psalm/src/Psalm/Type/Reconciler.php b/vendor/vimeo/psalm/src/Psalm/Type/Reconciler.php index 9bf4d261..074ef233 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/Reconciler.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/Reconciler.php @@ -761,7 +761,7 @@ class Reconciler return null; } - $new_base_type_candidate = $existing_key_type_part->getGenericValueType(); + $new_base_type_candidate = $existing_key_type_part->getGenericValueType(true); } else { $array_properties = $existing_key_type_part->properties; diff --git a/vendor/vimeo/psalm/src/Psalm/Type/UnionTrait.php b/vendor/vimeo/psalm/src/Psalm/Type/UnionTrait.php index bd7a1bdb..3361c2ba 100644 --- a/vendor/vimeo/psalm/src/Psalm/Type/UnionTrait.php +++ b/vendor/vimeo/psalm/src/Psalm/Type/UnionTrait.php @@ -34,6 +34,7 @@ use Psalm\Type\Atomic\TMixed; use Psalm\Type\Atomic\TNamedObject; use Psalm\Type\Atomic\TNever; use Psalm\Type\Atomic\TNonEmptyLowercaseString; +use Psalm\Type\Atomic\TNonEmptyString; use Psalm\Type\Atomic\TNonspecificLiteralInt; use Psalm\Type\Atomic\TNonspecificLiteralString; use Psalm\Type\Atomic\TString; @@ -52,6 +53,8 @@ use function reset; use function sort; use function strpos; +use const ARRAY_FILTER_USE_BOTH; + /** * @psalm-immutable * @psalm-import-type TProperties from Union @@ -795,9 +798,20 @@ trait UnionTrait /** * @psalm-mutation-free */ - public function isMixed(): bool + public function isMixed(bool $check_templates = false): bool { - return isset($this->types['mixed']) && count($this->types) === 1; + return count( + array_filter( + $this->types, + static fn($type, $key): bool => $key === 'mixed' + || $type instanceof TMixed + || ($check_templates + && $type instanceof TTemplateParam + && $type->as->isMixed() + ), + ARRAY_FILTER_USE_BOTH, + ), + ) === count($this->types); } /** @@ -1016,6 +1030,25 @@ trait UnionTrait ) === count($this->types); } + /** + * @psalm-mutation-free + * @return bool true if this is a string + */ + public function isNonEmptyString(bool $check_templates = false): bool + { + return count( + array_filter( + $this->types, + static fn($type): bool => $type instanceof TNonEmptyString + || ($type instanceof TLiteralString && $type->value !== '') + || ($check_templates + && $type instanceof TTemplateParam + && $type->as->isNonEmptyString() + ) + ), + ) === count($this->types); + } + /** * @psalm-mutation-free * @return bool true if this is a boolean diff --git a/vendor/vimeo/psalm/stubs/CoreGenericClasses.phpstub b/vendor/vimeo/psalm/stubs/CoreGenericClasses.phpstub index 528f59ab..3fd64fb3 100644 --- a/vendor/vimeo/psalm/stubs/CoreGenericClasses.phpstub +++ b/vendor/vimeo/psalm/stubs/CoreGenericClasses.phpstub @@ -531,3 +531,93 @@ final class ReturnTypeWillChange public function __construct() {} } +class DateInterval +{ + /** + * Number of years + * @var int + * @readonly + */ + public $y; + + /** + * Number of months + * @var int + * @readonly + */ + public $m; + + /** + * Number of days + * @var int + * @readonly + */ + public $d; + + /** + * Number of hours + * @var int + * @readonly + */ + public $h; + + /** + * Number of minutes + * @var int + * @readonly + */ + public $i; + + /** + * Number of seconds + * @var int + * @readonly + */ + public $s; + + /** + * Number of microseconds + * @since 7.1.0 + * @var float + * @readonly + */ + public $f; + + /** + * Is 1 if the interval is inverted and 0 otherwise + * @var int + * @readonly + */ + public $invert; + + /** + * Total number of days the interval spans. If this is unknown, days will be FALSE. + * @var int|false + * @readonly + */ + public $days; + + /** + * @throws Exception when the $duration cannot be parsed as an interval. + * @link https://php.net/manual/en/dateinterval.construct.php + */ + public function __construct(string $duration = '') {} + + /** + * Formats the interval + * @return string + * @link https://php.net/manual/en/dateinterval.format.php + * @psalm-pure + */ + public function format(string $format = ''): string {} + + /** + * Sets up a DateInterval from the relative parts of the string + * @return DateInterval|false Returns a new {@link https://www.php.net/manual/en/class.dateinterval.php DateInterval} + * instance on success, or FALSE on failure. + * @link https://php.net/manual/en/dateinterval.createfromdatestring.php + * @psalm-ignore-falsable-return + */ + public static function createFromDateString(string $datetime = ''): DateInterval|false {} +} + diff --git a/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub b/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub index f9640b06..5e2640e1 100644 --- a/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub +++ b/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub @@ -122,13 +122,27 @@ function array_diff_assoc(array $array, array ...$arrays) * * @param array $array * - * @return array + * @return ($array is non-empty-array ? non-empty-array : array) * @psalm-pure */ function array_flip(array $array) { } +/** + * @psalm-template TKey as array-key + * @psalm-template TValue + * @psalm-template TArray as array + * + * @param TArray $array + * + * @return (TArray is non-empty-array ? non-empty-array : array) + * @psalm-pure + */ +function array_unique(array $array, int $flags = 0) +{ +} + /** * @psalm-template TKey as array-key * @psalm-template TArray as array @@ -545,17 +559,6 @@ function abs($num) {} */ function range($start, $end, $step = 1) {} -/** - * @psalm-pure - * - * @return ( - * $format is 'd'|'j'|'N'|'w'|'z'|'W'|'m'|'n'|'t'|'L'|'o'|'Y'|'y'|'B'|'g'|'G'|'h'|'H'|'i'|'s'|'u'|'v'|'Z'|'U'|'I' - * ? numeric-string - * : ($timestamp is numeric ? string : string|false) - * ) - */ -function date(string $format, int $timestamp = 0) {} - /** * @psalm-pure * @@ -624,12 +627,23 @@ function substr_replace($string, $replace, $offset, $length = null) {} /** * @psalm-pure - * * @param string $haystack - * + * @param string $needle + * @param int $offset + * @psalm-assert-if-true =non-empty-string $haystack * @psalm-return positive-int|0|false */ -function strpos($haystack, $needle, int $offset = 0) : int|false {} +function strpos(string $haystack, string $needle, int $offset = 0) {} + +/** + * @psalm-pure + * @param string $haystack + * @param string $needle + * @param int $offset + * @psalm-assert-if-true =non-empty-string $haystack + * @psalm-return positive-int|0|false + */ +function stripos(string $haystack, string $needle, int $offset = 0) {} /** * @psalm-pure @@ -1050,12 +1064,40 @@ function str_shuffle(string $string): string {} /** * @psalm-pure - * @return ($length is positive-int ? list : false) + * @param positive-int $length + * @return non-empty-list * * @psalm-flow ($string) -> return */ function str_split(string $string, int $length = 1) {} +/** + * @psalm-pure + * @template T as string + * @param T $needle + * @psalm-assert-if-true =(T is '' ? string : non-empty-string) $haystack + * @return ($needle is '' ? true : ($haystack is '' ? false : bool)) + */ +function str_starts_with(string $haystack, string $needle): bool {} + +/** + * @psalm-pure + * @template T as string + * @param T $needle + * @psalm-assert-if-true =(T is '' ? string : non-empty-string) $haystack + * @return ($needle is '' ? true : ($haystack is '' ? false : bool)) + */ +function str_ends_with(string $haystack, string $needle): bool {} + +/** + * @psalm-pure + * @template T as string + * @param T $needle + * @psalm-assert-if-true =(T is '' ? string : non-empty-string) $haystack + * @return ($needle is '' ? true : ($haystack is '' ? false : bool)) + */ +function str_contains(string $haystack, string $needle): bool {} + /** * @psalm-pure * @return string|false @@ -1459,15 +1501,19 @@ function ldap_escape(string $value, string $ignore = "", int $flags = 0) : strin /** * @psalm-pure * + * @param int<1, 2147483647> $depth * @return mixed * @psalm-flow ($json) -> return */ function json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0) {} /** + * The conditional return type below relies on the fact that JSON_THROW_ON_ERROR is + * the highest-valued of JSON constants * @psalm-pure * - * @return ($flags is 4194304 ? non-empty-string : non-empty-string|false) + * @param int<1, 2147483647> $depth + * @return ($flags is int<4194304, 8388607> ? non-empty-string : non-empty-string|false) * * @psalm-flow ($value) -> return * @psalm-ignore-falsable-return diff --git a/vendor/vimeo/psalm/stubs/CoreGenericIterators.phpstub b/vendor/vimeo/psalm/stubs/CoreGenericIterators.phpstub index c69583d9..43a7bb1f 100644 --- a/vendor/vimeo/psalm/stubs/CoreGenericIterators.phpstub +++ b/vendor/vimeo/psalm/stubs/CoreGenericIterators.phpstub @@ -114,7 +114,7 @@ class IteratorIterator implements OuterIterator { /** * @param TIterator $iterator */ - public function __construct(Traversable $iterator) {} + public function __construct(Traversable $iterator, ?string $class = null) {} /** * @return TValue|null current value or null when iterator is drained diff --git a/vendor/vimeo/psalm/stubs/Php82.phpstub b/vendor/vimeo/psalm/stubs/Php82.phpstub index 40d60e3e..8696bd08 100644 --- a/vendor/vimeo/psalm/stubs/Php82.phpstub +++ b/vendor/vimeo/psalm/stubs/Php82.phpstub @@ -45,4 +45,13 @@ namespace { { public function __construct() {} } + + /** + * @psalm-pure + * @param positive-int $length + * @return list + * + * @psalm-flow ($string) -> return + */ + function str_split(string $string, int $length = 1) {} } diff --git a/vendor/vimeo/psalm/stubs/extensions/mysqli.phpstub b/vendor/vimeo/psalm/stubs/extensions/mysqli.phpstub index a5ec2f54..1569a524 100644 --- a/vendor/vimeo/psalm/stubs/extensions/mysqli.phpstub +++ b/vendor/vimeo/psalm/stubs/extensions/mysqli.phpstub @@ -1,5 +1,13 @@ |numeric-string + */ + public int|string $affected_rows; +} + /** * @template TValue * @@ -7,6 +15,11 @@ */ class mysqli_result implements Traversable { + /** + * @var int<0, max>|numeric-string + */ + public int|string $num_rows; + /** * @psalm-taint-sink callable $class * @@ -18,6 +31,44 @@ class mysqli_result implements Traversable function fetch_object(string $class = stdClass::class, array $constructor_args = []): object|false|null {} } +class mysqli_stmt +{ + /** + * @var int<-1, max>|numeric-string + */ + public int|string $affected_rows; + + public int $errno; + + /** + * @var list + */ + public $error_list; + + public string $error; + + /** + * @var 0|positive-int + */ + public int $field_count; + + public int|string $insert_id; + + /** + * @var int<0,max>|numeric-string + */ + public int|string $num_rows; + + /** + * @var 0|positive-int + */ + public int $param_count; + + /** + * @var non-empty-string + */ + public string $sqlstate; +} /** * @psalm-taint-sink callable $class diff --git a/vendor/vimeo/psalm/stubs/extensions/simplexml.phpstub b/vendor/vimeo/psalm/stubs/extensions/simplexml.phpstub index 7ff39239..5c2fb2f5 100644 --- a/vendor/vimeo/psalm/stubs/extensions/simplexml.phpstub +++ b/vendor/vimeo/psalm/stubs/extensions/simplexml.phpstub @@ -53,6 +53,7 @@ class SimpleXMLElement implements Traversable, Countable final public function __construct(string $data, int $options = 0, bool $dataIsURL = false, string $namespaceOrPrefix = '', bool $isPrefix = false) {} + /** @psalm-ignore-nullable-return */ public function addChild(string $qualifiedName, ?string $value = null, ?string $namespace = null): ?SimpleXMLElement {} public function addAttribute(string $qualifiedName, string $value, ?string $namespace = null): void {} diff --git a/www/composer.json b/www/composer.json index 5c05400e..e9c111e2 100644 --- a/www/composer.json +++ b/www/composer.json @@ -26,6 +26,7 @@ "require": { "egrajp/smarty-extended": "^4.3", "php": ">=8.1", - "gullevek/dotenv": "^2.0" + "gullevek/dotenv": "^2.0", + "psr/log": "^2.0 || ^3.0" } } diff --git a/www/composer.lock b/www/composer.lock index 3af0eac2..d3fa2255 100644 --- a/www/composer.lock +++ b/www/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "88bf0aa9b348a55a525b96fcaed7b5a9", + "content-hash": "3613982c10e8a26141e775ac6bd16656", "packages": [ { "name": "egrajp/smarty-extended", @@ -89,6 +89,56 @@ "source": "https://github.com/gullevek/dotEnv/tree/v2.0.8" }, "time": "2023-03-03T00:32:02+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" } ], "packages-dev": [ @@ -164,16 +214,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.0", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { @@ -211,7 +261,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { @@ -219,20 +269,20 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { "name": "nikic/php-parser", - "version": "v4.15.3", + "version": "v4.15.5", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "shasum": "" }, "require": { @@ -273,9 +323,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" }, - "time": "2023-01-16T22:05:37+00:00" + "time": "2023-05-19T20:20:00+00:00" }, { "name": "phar-io/manifest", @@ -390,16 +440,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.25", + "version": "9.2.26", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954" + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e2b40518197a8c0d4b08bc34dfff1c99c508954", - "reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "shasum": "" }, "require": { @@ -421,8 +471,8 @@ "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", "extra": { @@ -455,7 +505,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.25" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" }, "funding": [ { @@ -463,7 +513,7 @@ "type": "github" } ], - "time": "2023-02-25T05:32:00+00:00" + "time": "2023-03-06T12:58:08+00:00" }, { "name": "phpunit/php-file-iterator", @@ -708,16 +758,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.4", + "version": "9.6.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d" + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9125ee085b6d95e78277dc07aa1f46f9e0607b8d", - "reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", "shasum": "" }, "require": { @@ -750,8 +800,8 @@ "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -790,7 +840,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.4" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" }, "funding": [ { @@ -806,7 +857,7 @@ "type": "tidelift" } ], - "time": "2023-02-27T13:06:37+00:00" + "time": "2023-05-11T05:14:45+00:00" }, { "name": "sebastian/cli-parser", @@ -1108,16 +1159,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -1162,7 +1213,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { @@ -1170,7 +1221,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { "name": "sebastian/environment", diff --git a/www/vendor/composer/autoload_classmap.php b/www/vendor/composer/autoload_classmap.php index 7a6e31d7..04c4c89c 100644 --- a/www/vendor/composer/autoload_classmap.php +++ b/www/vendor/composer/autoload_classmap.php @@ -43,6 +43,7 @@ return array( 'CoreLibs\\DB\\SQL\\PgSQL' => $baseDir . '/lib/CoreLibs/DB/SQL/PgSQL.php', 'CoreLibs\\Debug\\FileWriter' => $baseDir . '/lib/CoreLibs/Debug/FileWriter.php', 'CoreLibs\\Debug\\Logging' => $baseDir . '/lib/CoreLibs/Debug/Logging.php', + 'CoreLibs\\Debug\\LoggingLegacy' => $baseDir . '/lib/CoreLibs/Debug/LoggingLegacy.php', 'CoreLibs\\Debug\\MemoryUsage' => $baseDir . '/lib/CoreLibs/Debug/MemoryUsage.php', 'CoreLibs\\Debug\\RunningTime' => $baseDir . '/lib/CoreLibs/Debug/RunningTime.php', 'CoreLibs\\Debug\\Support' => $baseDir . '/lib/CoreLibs/Debug/Support.php', @@ -55,6 +56,9 @@ return array( 'CoreLibs\\Language\\Core\\StringReader' => $baseDir . '/lib/CoreLibs/Language/Core/StringReader.php', 'CoreLibs\\Language\\GetLocale' => $baseDir . '/lib/CoreLibs/Language/GetLocale.php', 'CoreLibs\\Language\\L10n' => $baseDir . '/lib/CoreLibs/Language/L10n.php', + 'CoreLibs\\Logging\\Logger\\Flag' => $baseDir . '/lib/CoreLibs/Logging/Logger/Flag.php', + 'CoreLibs\\Logging\\Logger\\Level' => $baseDir . '/lib/CoreLibs/Logging/Logger/Level.php', + 'CoreLibs\\Logging\\Logging' => $baseDir . '/lib/CoreLibs/Logging/Logging.php', 'CoreLibs\\Output\\Form\\Elements' => $baseDir . '/lib/CoreLibs/Output/Form/Elements.php', 'CoreLibs\\Output\\Form\\Generate' => $baseDir . '/lib/CoreLibs/Output/Form/Generate.php', 'CoreLibs\\Output\\Form\\TableArrays\\EditAccess' => $baseDir . '/lib/CoreLibs/Output/Form/TableArrays/EditAccess.php', diff --git a/www/vendor/composer/autoload_psr4.php b/www/vendor/composer/autoload_psr4.php index def4fddf..81c4c26f 100644 --- a/www/vendor/composer/autoload_psr4.php +++ b/www/vendor/composer/autoload_psr4.php @@ -8,6 +8,7 @@ $baseDir = dirname($vendorDir); return array( 'gullevek\\dotenv\\' => array($vendorDir . '/gullevek/dotenv/src'), 'gullevek\\dotEnv\\' => array($vendorDir . '/gullevek/dotenv/src'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/src'), 'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'), 'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'), 'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'), diff --git a/www/vendor/composer/autoload_static.php b/www/vendor/composer/autoload_static.php index 7ff5acf8..095f108a 100644 --- a/www/vendor/composer/autoload_static.php +++ b/www/vendor/composer/autoload_static.php @@ -19,6 +19,7 @@ class ComposerStaticInit10fe8fe2ec4017b8644d2b64bcf398b9 ), 'P' => array ( + 'Psr\\Log\\' => 8, 'PhpParser\\' => 10, ), 'D' => @@ -37,6 +38,10 @@ class ComposerStaticInit10fe8fe2ec4017b8644d2b64bcf398b9 array ( 0 => __DIR__ . '/..' . '/gullevek/dotenv/src', ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/src', + ), 'PhpParser\\' => array ( 0 => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser', @@ -89,6 +94,7 @@ class ComposerStaticInit10fe8fe2ec4017b8644d2b64bcf398b9 'CoreLibs\\DB\\SQL\\PgSQL' => __DIR__ . '/../..' . '/lib/CoreLibs/DB/SQL/PgSQL.php', 'CoreLibs\\Debug\\FileWriter' => __DIR__ . '/../..' . '/lib/CoreLibs/Debug/FileWriter.php', 'CoreLibs\\Debug\\Logging' => __DIR__ . '/../..' . '/lib/CoreLibs/Debug/Logging.php', + 'CoreLibs\\Debug\\LoggingLegacy' => __DIR__ . '/../..' . '/lib/CoreLibs/Debug/LoggingLegacy.php', 'CoreLibs\\Debug\\MemoryUsage' => __DIR__ . '/../..' . '/lib/CoreLibs/Debug/MemoryUsage.php', 'CoreLibs\\Debug\\RunningTime' => __DIR__ . '/../..' . '/lib/CoreLibs/Debug/RunningTime.php', 'CoreLibs\\Debug\\Support' => __DIR__ . '/../..' . '/lib/CoreLibs/Debug/Support.php', @@ -101,6 +107,9 @@ class ComposerStaticInit10fe8fe2ec4017b8644d2b64bcf398b9 'CoreLibs\\Language\\Core\\StringReader' => __DIR__ . '/../..' . '/lib/CoreLibs/Language/Core/StringReader.php', 'CoreLibs\\Language\\GetLocale' => __DIR__ . '/../..' . '/lib/CoreLibs/Language/GetLocale.php', 'CoreLibs\\Language\\L10n' => __DIR__ . '/../..' . '/lib/CoreLibs/Language/L10n.php', + 'CoreLibs\\Logging\\Logger\\Flag' => __DIR__ . '/../..' . '/lib/CoreLibs/Logging/Logger/Flag.php', + 'CoreLibs\\Logging\\Logger\\Level' => __DIR__ . '/../..' . '/lib/CoreLibs/Logging/Logger/Level.php', + 'CoreLibs\\Logging\\Logging' => __DIR__ . '/../..' . '/lib/CoreLibs/Logging/Logging.php', 'CoreLibs\\Output\\Form\\Elements' => __DIR__ . '/../..' . '/lib/CoreLibs/Output/Form/Elements.php', 'CoreLibs\\Output\\Form\\Generate' => __DIR__ . '/../..' . '/lib/CoreLibs/Output/Form/Generate.php', 'CoreLibs\\Output\\Form\\TableArrays\\EditAccess' => __DIR__ . '/../..' . '/lib/CoreLibs/Output/Form/TableArrays/EditAccess.php', diff --git a/www/vendor/composer/installed.json b/www/vendor/composer/installed.json index 976dd13f..916dedc0 100644 --- a/www/vendor/composer/installed.json +++ b/www/vendor/composer/installed.json @@ -165,17 +165,17 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.0", - "version_normalized": "1.11.0.0", + "version": "1.11.1", + "version_normalized": "1.11.1.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { @@ -190,7 +190,7 @@ "doctrine/common": "^2.13.3 || ^3.2.2", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, - "time": "2022-03-03T13:19:32+00:00", + "time": "2023-03-08T13:26:56+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -215,7 +215,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { @@ -227,17 +227,17 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.3", - "version_normalized": "4.15.3.0", + "version": "v4.15.5", + "version_normalized": "4.15.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "shasum": "" }, "require": { @@ -248,7 +248,7 @@ "ircmaxell/php-yacc": "^0.0.7", "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, - "time": "2023-01-16T22:05:37+00:00", + "time": "2023-05-19T20:20:00+00:00", "bin": [ "bin/php-parse" ], @@ -280,7 +280,7 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" }, "install-path": "../nikic/php-parser" }, @@ -403,17 +403,17 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.25", - "version_normalized": "9.2.25.0", + "version": "9.2.26", + "version_normalized": "9.2.26.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954" + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e2b40518197a8c0d4b08bc34dfff1c99c508954", - "reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "shasum": "" }, "require": { @@ -435,10 +435,10 @@ "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, - "time": "2023-02-25T05:32:00+00:00", + "time": "2023-03-06T12:58:08+00:00", "type": "library", "extra": { "branch-alias": { @@ -471,7 +471,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.25" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" }, "funding": [ { @@ -736,17 +736,17 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.4", - "version_normalized": "9.6.4.0", + "version": "9.6.8", + "version_normalized": "9.6.8.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d" + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9125ee085b6d95e78277dc07aa1f46f9e0607b8d", - "reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", "shasum": "" }, "require": { @@ -779,10 +779,10 @@ "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, - "time": "2023-02-27T13:06:37+00:00", + "time": "2023-05-11T05:14:45+00:00", "bin": [ "phpunit" ], @@ -821,7 +821,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.4" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" }, "funding": [ { @@ -839,6 +840,59 @@ ], "install-path": "../phpunit/phpunit" }, + { + "name": "psr/log", + "version": "3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "time": "2021-07-14T16:46:02+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "install-path": "../psr/log" + }, { "name": "sebastian/cli-parser", "version": "1.0.1", @@ -1154,17 +1208,17 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", - "version_normalized": "4.0.4.0", + "version": "4.0.5", + "version_normalized": "4.0.5.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -1174,7 +1228,7 @@ "phpunit/phpunit": "^9.3", "symfony/process": "^4.2 || ^5" }, - "time": "2020-10-26T13:10:38+00:00", + "time": "2023-05-07T05:35:17+00:00", "type": "library", "extra": { "branch-alias": { @@ -1211,7 +1265,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { diff --git a/www/vendor/composer/installed.php b/www/vendor/composer/installed.php index ab21956b..4d05e1ca 100644 --- a/www/vendor/composer/installed.php +++ b/www/vendor/composer/installed.php @@ -47,18 +47,18 @@ 'dev_requirement' => false, ), 'myclabs/deep-copy' => array( - 'pretty_version' => '1.11.0', - 'version' => '1.11.0.0', - 'reference' => '14daed4296fae74d9e3201d2c4925d1acb7aa614', + 'pretty_version' => '1.11.1', + 'version' => '1.11.1.0', + 'reference' => '7284c22080590fb39f2ffa3e9057f10a4ddd0e0c', 'type' => 'library', 'install_path' => __DIR__ . '/../myclabs/deep-copy', 'aliases' => array(), 'dev_requirement' => true, ), 'nikic/php-parser' => array( - 'pretty_version' => 'v4.15.3', - 'version' => '4.15.3.0', - 'reference' => '570e980a201d8ed0236b0a62ddf2c9cbb2034039', + 'pretty_version' => 'v4.15.5', + 'version' => '4.15.5.0', + 'reference' => '11e2663a5bc9db5d714eedb4277ee300403b4a9e', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), @@ -83,9 +83,9 @@ 'dev_requirement' => true, ), 'phpunit/php-code-coverage' => array( - 'pretty_version' => '9.2.25', - 'version' => '9.2.25.0', - 'reference' => '0e2b40518197a8c0d4b08bc34dfff1c99c508954', + 'pretty_version' => '9.2.26', + 'version' => '9.2.26.0', + 'reference' => '443bc6912c9bd5b409254a40f4b0f4ced7c80ea1', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-code-coverage', 'aliases' => array(), @@ -128,14 +128,23 @@ 'dev_requirement' => true, ), 'phpunit/phpunit' => array( - 'pretty_version' => '9.6.4', - 'version' => '9.6.4.0', - 'reference' => '9125ee085b6d95e78277dc07aa1f46f9e0607b8d', + 'pretty_version' => '9.6.8', + 'version' => '9.6.8.0', + 'reference' => '17d621b3aff84d0c8b62539e269e87d8d5baa76e', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/phpunit', 'aliases' => array(), 'dev_requirement' => true, ), + 'psr/log' => array( + 'pretty_version' => '3.0.0', + 'version' => '3.0.0.0', + 'reference' => 'fe5ea303b0887d5caefd3d431c3e61ad47037001', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'sebastian/cli-parser' => array( 'pretty_version' => '1.0.1', 'version' => '1.0.1.0', @@ -182,9 +191,9 @@ 'dev_requirement' => true, ), 'sebastian/diff' => array( - 'pretty_version' => '4.0.4', - 'version' => '4.0.4.0', - 'reference' => '3461e3fccc7cfdfc2720be910d3bd73c69be590d', + 'pretty_version' => '4.0.5', + 'version' => '4.0.5.0', + 'reference' => '74be17022044ebaaecfdf0c5cd504fc9cd5a7131', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/diff', 'aliases' => array(), diff --git a/www/vendor/myclabs/deep-copy/README.md b/www/vendor/myclabs/deep-copy/README.md index 503e93df..94aaa06d 100644 --- a/www/vendor/myclabs/deep-copy/README.md +++ b/www/vendor/myclabs/deep-copy/README.md @@ -186,6 +186,9 @@ $matcher = new TypeMatcher('Doctrine\Common\Collections\Collection'); - `DeepCopy\Filter` applies a transformation to the object attribute matched by `DeepCopy\Matcher` - `DeepCopy\TypeFilter` applies a transformation to any element matched by `DeepCopy\TypeMatcher` +By design, matching a filter will stop the chain of filters (i.e. the next ones will not be applied). +Using the ([`ChainableFilter`](#chainablefilter-filter)) won't stop the chain of filters. + #### `SetNullFilter` (filter) @@ -226,6 +229,34 @@ $copy = $copier->copy($object); ``` +#### `ChainableFilter` (filter) + +If you use cloning on proxy classes, you might want to apply two filters for: +1. loading the data +2. applying a transformation + +You can use the `ChainableFilter` as a decorator of the proxy loader filter, which won't stop the chain of filters (i.e. +the next ones may be applied). + + +```php +use DeepCopy\DeepCopy; +use DeepCopy\Filter\ChainableFilter; +use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; +use DeepCopy\Filter\SetNullFilter; +use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; +use DeepCopy\Matcher\PropertyNameMatcher; + +$copier = new DeepCopy(); +$copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher()); +$copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id')); + +$copy = $copier->copy($object); + +echo $copy->id; // null +``` + + #### `DoctrineCollectionFilter` (filter) If you use Doctrine and want to copy an entity, you will need to use the `DoctrineCollectionFilter`: @@ -268,6 +299,8 @@ Doctrine proxy class (...\\\_\_CG\_\_\Proxy). You can use the `DoctrineProxyFilter` to load the actual entity behind the Doctrine proxy class. **Make sure, though, to put this as one of your very first filters in the filter chain so that the entity is loaded before other filters are applied!** +We recommend to decorate the `DoctrineProxyFilter` with the `ChainableFilter` to allow applying other filters to the +cloned lazy loaded entities. ```php use DeepCopy\DeepCopy; @@ -275,7 +308,7 @@ use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; $copier = new DeepCopy(); -$copier->addFilter(new DoctrineProxyFilter(), new DoctrineProxyMatcher()); +$copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher()); $copy = $copier->copy($object); diff --git a/www/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php b/www/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php index 5e68c64e..6e766d80 100644 --- a/www/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php +++ b/www/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php @@ -7,6 +7,7 @@ use DateInterval; use DateTimeInterface; use DateTimeZone; use DeepCopy\Exception\CloneException; +use DeepCopy\Filter\ChainableFilter; use DeepCopy\Filter\Filter; use DeepCopy\Matcher\Matcher; use DeepCopy\Reflection\ReflectionHelper; @@ -239,6 +240,10 @@ class DeepCopy } ); + if ($filter instanceof ChainableFilter) { + continue; + } + // If a filter matches, we stop processing this property return; } diff --git a/www/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ChainableFilter.php b/www/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ChainableFilter.php new file mode 100644 index 00000000..4e3f7bbc --- /dev/null +++ b/www/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ChainableFilter.php @@ -0,0 +1,24 @@ +filter = $filter; + } + + public function apply($object, $property, $objectCopier) + { + $this->filter->apply($object, $property, $objectCopier); + } +} diff --git a/www/vendor/nikic/php-parser/grammar/php7.y b/www/vendor/nikic/php-parser/grammar/php7.y index 1f9b4bdd..fc7862c3 100644 --- a/www/vendor/nikic/php-parser/grammar/php7.y +++ b/www/vendor/nikic/php-parser/grammar/php7.y @@ -518,7 +518,8 @@ new_elseif_list: ; new_elseif: - T_ELSEIF '(' expr ')' ':' inner_statement_list { $$ = Stmt\ElseIf_[$3, $6]; } + T_ELSEIF '(' expr ')' ':' inner_statement_list + { $$ = Stmt\ElseIf_[$3, $6]; $this->fixupAlternativeElse($$); } ; else_single: @@ -528,7 +529,8 @@ else_single: new_else_single: /* empty */ { $$ = null; } - | T_ELSE ':' inner_statement_list { $$ = Stmt\Else_[$3]; } + | T_ELSE ':' inner_statement_list + { $$ = Stmt\Else_[$3]; $this->fixupAlternativeElse($$); } ; foreach_variable: diff --git a/www/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php b/www/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php index de9aae7e..69f35332 100644 --- a/www/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php +++ b/www/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php @@ -19,6 +19,8 @@ class Param implements PhpParser\Builder protected $variadic = false; + protected $flags = 0; + /** @var Node\AttributeGroup[] */ protected $attributeGroups = []; @@ -95,6 +97,50 @@ class Param implements PhpParser\Builder return $this; } + /** + * Makes the (promoted) parameter public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PUBLIC); + + return $this; + } + + /** + * Makes the (promoted) parameter protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PROTECTED); + + return $this; + } + + /** + * Makes the (promoted) parameter private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PRIVATE); + + return $this; + } + + /** + * Makes the (promoted) parameter readonly. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeReadonly() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_READONLY); + + return $this; + } + /** * Adds an attribute group. * @@ -116,7 +162,7 @@ class Param implements PhpParser\Builder public function getNode() : Node { return new Node\Param( new Node\Expr\Variable($this->name), - $this->default, $this->type, $this->byRef, $this->variadic, [], 0, $this->attributeGroups + $this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups ); } } diff --git a/www/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php b/www/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php index 48deff23..c6b9abd0 100644 --- a/www/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php +++ b/www/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php @@ -1826,7 +1826,7 @@ class Php7 extends \PhpParser\ParserAbstract $this->semStack[$stackPos-(2-1)][] = $this->semStack[$stackPos-(2-2)]; $this->semValue = $this->semStack[$stackPos-(2-1)]; }, 266 => function ($stackPos) { - $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos-(6-3)], $this->semStack[$stackPos-(6-6)], $this->startAttributeStack[$stackPos-(6-1)] + $this->endAttributes); + $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos-(6-3)], $this->semStack[$stackPos-(6-6)], $this->startAttributeStack[$stackPos-(6-1)] + $this->endAttributes); $this->fixupAlternativeElse($this->semValue); }, 267 => function ($stackPos) { $this->semValue = null; @@ -1838,7 +1838,7 @@ class Php7 extends \PhpParser\ParserAbstract $this->semValue = null; }, 270 => function ($stackPos) { - $this->semValue = new Stmt\Else_($this->semStack[$stackPos-(3-3)], $this->startAttributeStack[$stackPos-(3-1)] + $this->endAttributes); + $this->semValue = new Stmt\Else_($this->semStack[$stackPos-(3-3)], $this->startAttributeStack[$stackPos-(3-1)] + $this->endAttributes); $this->fixupAlternativeElse($this->semValue); }, 271 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos-(1-1)], false); diff --git a/www/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php b/www/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php index 301d3c6a..9f9d00c7 100644 --- a/www/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php +++ b/www/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php @@ -16,9 +16,12 @@ use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassConst; use PhpParser\Node\Stmt\ClassMethod; +use PhpParser\Node\Stmt\Else_; +use PhpParser\Node\Stmt\ElseIf_; use PhpParser\Node\Stmt\Enum_; use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Namespace_; +use PhpParser\Node\Stmt\Nop; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\TryCatch; use PhpParser\Node\Stmt\UseUse; @@ -876,6 +879,24 @@ abstract class ParserAbstract implements Parser return $attributes; } + /** @param ElseIf_|Else_ $node */ + protected function fixupAlternativeElse($node) { + // Make sure a trailing nop statement carrying comments is part of the node. + $numStmts = \count($node->stmts); + if ($numStmts !== 0 && $node->stmts[$numStmts - 1] instanceof Nop) { + $nopAttrs = $node->stmts[$numStmts - 1]->getAttributes(); + if (isset($nopAttrs['endLine'])) { + $node->setAttribute('endLine', $nopAttrs['endLine']); + } + if (isset($nopAttrs['endFilePos'])) { + $node->setAttribute('endFilePos', $nopAttrs['endFilePos']); + } + if (isset($nopAttrs['endTokenPos'])) { + $node->setAttribute('endTokenPos', $nopAttrs['endTokenPos']); + } + } + } + protected function checkClassModifier($a, $b, $modifierPos) { try { Class_::verifyClassModifier($a, $b); diff --git a/www/vendor/phpunit/php-code-coverage/ChangeLog.md b/www/vendor/phpunit/php-code-coverage/ChangeLog-9.2.md similarity index 99% rename from www/vendor/phpunit/php-code-coverage/ChangeLog.md rename to www/vendor/phpunit/php-code-coverage/ChangeLog-9.2.md index 35ef8119..34587c05 100644 --- a/www/vendor/phpunit/php-code-coverage/ChangeLog.md +++ b/www/vendor/phpunit/php-code-coverage/ChangeLog-9.2.md @@ -2,6 +2,12 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. +## [9.2.26] - 2023-03-06 + +### Changed + +* Improved the legend on the file pages of the HTML code coverage report + ## [9.2.25] - 2023-02-25 ### Fixed @@ -470,6 +476,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt * This component is no longer supported on PHP 7.1 +[9.2.26]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.25...9.2.26 [9.2.25]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.24...9.2.25 [9.2.24]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.23...9.2.24 [9.2.23]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.22...9.2.23 diff --git a/www/vendor/phpunit/php-code-coverage/composer.json b/www/vendor/phpunit/php-code-coverage/composer.json index 6db6936f..d6f10795 100644 --- a/www/vendor/phpunit/php-code-coverage/composer.json +++ b/www/vendor/phpunit/php-code-coverage/composer.json @@ -46,8 +46,8 @@ "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "autoload": { "classmap": [ diff --git a/www/vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/File.php b/www/vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/File.php index 101a9ada..b59dc89d 100644 --- a/www/vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/File.php +++ b/www/vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/File.php @@ -134,7 +134,7 @@ final class File extends Renderer [ 'items' => $this->renderItems($node), 'lines' => $this->renderSourceWithLineCoverage($node), - 'legend' => '

ExecutedNot ExecutedDead Code

', + 'legend' => '

Covered by small (and larger) testsCovered by medium (and large) testsCovered by large tests (and tests of unknown size)Not coveredNot coverable

', 'structure' => '', ] ); diff --git a/www/vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/css/style.css b/www/vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/css/style.css index 5dc62ccf..526cac0d 100644 --- a/www/vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/css/style.css +++ b/www/vendor/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/css/style.css @@ -128,3 +128,31 @@ table + .structure-heading { border-top: 1px solid lightgrey; padding-top: 0.5em; } + +.legend { + font-weight: bold; + margin-right: 2px; + padding-left: 10px; + padding-right: 10px; + text-align: center; +} + +.covered-by-small-tests { + background-color: #99cb84; +} + +.covered-by-medium-tests { + background-color: #c3e3b5; +} + +.covered-by-large-tests { + background-color: #dff0d8; +} + +.not-covered { + background-color: #f2dede; +} + +.not-coverable { + background-color: #fcf8e3; +} diff --git a/www/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ExecutableLinesFindingVisitor.php b/www/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ExecutableLinesFindingVisitor.php index 506f2752..794084ff 100644 --- a/www/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ExecutableLinesFindingVisitor.php +++ b/www/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ExecutableLinesFindingVisitor.php @@ -88,12 +88,19 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract return; } + if ($node instanceof Node\Stmt\Interface_) { + foreach (range($node->getStartLine(), $node->getEndLine()) as $line) { + $this->unsets[$line] = true; + } + + return; + } + if ($node instanceof Node\Stmt\Declare_ || $node instanceof Node\Stmt\DeclareDeclare || $node instanceof Node\Stmt\Else_ || $node instanceof Node\Stmt\EnumCase || $node instanceof Node\Stmt\Finally_ || - $node instanceof Node\Stmt\Interface_ || $node instanceof Node\Stmt\Label || $node instanceof Node\Stmt\Namespace_ || $node instanceof Node\Stmt\Nop || diff --git a/www/vendor/phpunit/php-code-coverage/src/Version.php b/www/vendor/phpunit/php-code-coverage/src/Version.php index 7feb0a9c..20e8e550 100644 --- a/www/vendor/phpunit/php-code-coverage/src/Version.php +++ b/www/vendor/phpunit/php-code-coverage/src/Version.php @@ -22,7 +22,7 @@ final class Version public static function id(): string { if (self::$version === null) { - self::$version = (new VersionId('9.2.25', dirname(__DIR__)))->getVersion(); + self::$version = (new VersionId('9.2.26', dirname(__DIR__)))->getVersion(); } return self::$version; diff --git a/www/vendor/phpunit/phpunit/ChangeLog-8.5.md b/www/vendor/phpunit/phpunit/ChangeLog-8.5.md deleted file mode 100644 index a65e6a61..00000000 --- a/www/vendor/phpunit/phpunit/ChangeLog-8.5.md +++ /dev/null @@ -1,304 +0,0 @@ -# Changes in PHPUnit 8.5 - -All notable changes of the PHPUnit 8.5 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. - -## [8.5.33] - 2023-02-27 - -### Fixed - -* [#5186](https://github.com/sebastianbergmann/phpunit/issues/5186): SBOM does not validate - -## [8.5.32] - 2023-01-26 - -### Fixed - -* [#5120](https://github.com/sebastianbergmann/phpunit/issues/5120): Test Runner incorrectly treats `--testsuite` and `--list-tests` as not combinable options - -## [8.5.31] - 2022-10-28 - -### Fixed - -* [#5076](https://github.com/sebastianbergmann/phpunit/issues/5076): Test Runner does not warn about conflicting options - -## [8.5.30] - 2022-09-25 - -### Changed - -* The configuration generator now asks for a cache directory - -### Fixed - -* [#4913](https://github.com/sebastianbergmann/phpunit/issues/4913): Failed `assert()` should show a backtrace -* [#4966](https://github.com/sebastianbergmann/phpunit/issues/4966): `TestCase::assertSame()` (and related exact comparisons) must compare `float` exactly - -## [8.5.29] - 2022-08-22 - -### Changed - -* [#5033](https://github.com/sebastianbergmann/phpunit/issues/5033): Do not depend on phpspec/prophecy - -## [8.5.28] - 2022-07-29 - -### Fixed - -* [#5015](https://github.com/sebastianbergmann/phpunit/pull/5015): Ukraine banner unreadable on black background -* [#5016](https://github.com/sebastianbergmann/phpunit/issues/5016): PHPUnit 8.5.27 does not work on PHP 7.2.0-7.2.18 and PHP 7.3.0-7.3.5 - -## [8.5.27] - 2022-06-19 - -### Fixed - -* [#4950](https://github.com/sebastianbergmann/phpunit/issues/4950): False error on `atMost()` invocation rule without call -* [#4962](https://github.com/sebastianbergmann/phpunit/issues/4962): Ukraine banner unreadable on white background - -## [8.5.26] - 2022-04-01 - -### Fixed - -* [#4938](https://github.com/sebastianbergmann/phpunit/issues/4938): Test Double code generator does not handle `void` return type declaration on `__clone()` methods - -## [8.5.25] - 2022-03-16 - -### Fixed - -* [#4934](https://github.com/sebastianbergmann/phpunit/issues/4934): Code Coverage does not work with PHPUnit 8.5.24 PHAR on PHP 7 - -## [8.5.24] - 2022-03-05 - #StandWithUkraine - -### Changed - -* [#4874](https://github.com/sebastianbergmann/phpunit/pull/4874): `PHP_FLOAT_EPSILON` is now used instead of hardcoded `0.0000000001` in `PHPUnit\Framework\Constraint\IsIdentical` - -### Fixed - -* When the HTML code coverage report's configured low upper bound is larger than the high lower bound then the default values are used instead - -## [8.5.23] - 2022-01-21 - -### Fixed - -* [#4799](https://github.com/sebastianbergmann/phpunit/pull/4799): Memory leaks in `PHPUnit\Framework\TestSuite` class -* [#4857](https://github.com/sebastianbergmann/phpunit/pull/4857): Result of `debug_backtrace()` is not used correctly - -## [8.5.22] - 2021-12-25 - -### Changed - -* [#4812](https://github.com/sebastianbergmann/phpunit/issues/4812): Do not enforce time limits when a debugging session through DBGp is active -* [#4835](https://github.com/sebastianbergmann/phpunit/issues/4835): Support for `$GLOBALS['_composer_autoload_path']` introduced in Composer 2.2 - -### Fixed - -* [#4840](https://github.com/sebastianbergmann/phpunit/pull/4840): TestDox prettifying for class names does not correctly handle diacritics -* [#4846](https://github.com/sebastianbergmann/phpunit/pull/4846): Composer proxy script is not ignored - -## [8.5.21] - 2021-09-25 - -### Changed - -* PHPUnit no longer converts PHP deprecations to exceptions by default (configure `convertDeprecationsToExceptions="true"` to enable this) -* The PHPUnit XML configuration file generator now configures `convertDeprecationsToExceptions="true"` - -### Fixed - -* [#4772](https://github.com/sebastianbergmann/phpunit/pull/4772): TestDox HTML report not displayed correctly when browser has custom colour settings - -## [8.5.20] - 2021-08-31 - -### Fixed - -* [#4751](https://github.com/sebastianbergmann/phpunit/issues/4751): Configuration validation fails when using brackets in glob pattern - -## [8.5.19] - 2021-07-31 - -### Fixed - -* [#4740](https://github.com/sebastianbergmann/phpunit/issues/4740): `phpunit.phar` does not work with PHP 8.1 - -## [8.5.18] - 2021-07-19 - -### Fixed - -* [#4720](https://github.com/sebastianbergmann/phpunit/issues/4720): PHPUnit does not verify its own PHP extension requirements - -## [8.5.17] - 2021-06-23 - -### Changed - -* PHPUnit now errors out on startup when `PHP_VERSION` contains a value that is not compatible with `version_compare()`, for instance `X.Y.Z-(to be removed in future macOS)` - -## [8.5.16] - 2021-06-05 - -### Changed - -* The test result cache (the storage for which is implemented in `PHPUnit\Runner\DefaultTestResultCache`) no longer uses PHP's `serialize()` and `unserialize()` functions for persistence. It now uses a versioned JSON format instead that is independent of PHP implementation details (see [#3581](https://github.com/sebastianbergmann/phpunit/issues/3581) and [#4662](https://github.com/sebastianbergmann/phpunit/pull/4662) for examples why this is a problem). When PHPUnit tries to load the test result cache from a file that does not exist, or from a file that does not contain data in JSON format, or from a file that contains data in a JSON format version other than the one used by the currently running PHPUnit version, then this is considered to be a "cache miss". An empty `DefaultTestResultCache` object is created in this case. This should also prevent PHPUnit from crashing when trying to load a test result cache file created by a different version of PHPUnit (see [#4580](https://github.com/sebastianbergmann/phpunit/issues/4580) for example). - -### Fixed - -* [#4663](https://github.com/sebastianbergmann/phpunit/issues/4663): `TestCase::expectError()` works on PHP 7.3, but not on PHP >= 7.4 -* [#4678](https://github.com/sebastianbergmann/phpunit/pull/4678): Stubbed methods with `iterable` return types should return empty array by default -* [#4692](https://github.com/sebastianbergmann/phpunit/issues/4692): Annotations in single-line doc-comments are not handled correctly -* [#4694](https://github.com/sebastianbergmann/phpunit/issues/4694): `TestCase::getMockFromWsdl()` does not work with PHP 8.1-dev - -## [8.5.15] - 2021-03-17 - -### Fixed - -* [#4591](https://github.com/sebastianbergmann/phpunit/issues/4591): TeamCity logger logs warnings as test failures - -## [8.5.14] - 2021-01-17 - -### Fixed - -* [#4535](https://github.com/sebastianbergmann/phpunit/issues/4535): `getMockFromWsdl()` does not handle methods that do not have parameters correctly -* [#4572](https://github.com/sebastianbergmann/phpunit/issues/4572): Schema validation does not work with `%xx` sequences in path to `phpunit.xsd` -* [#4575](https://github.com/sebastianbergmann/phpunit/issues/4575): PHPUnit 8.5 incompatibility with PHP 8.1 - -## [8.5.13] - 2020-12-01 - -### Fixed - -* Running tests in isolated processes did not work with PHP 8 on Windows - -## [8.5.12] - 2020-11-30 - -### Changed - -* Changed PHP version constraint in `composer.json` from `^7.2` to `>=7.2` to allow the installation of PHPUnit 8.5 on PHP 8. Please note that the code coverage functionality is not available for PHPUnit 8.5 on PHP 8. - -### Fixed - -* [#4529](https://github.com/sebastianbergmann/phpunit/issues/4529): Debug mode of Xdebug 2 is not disabled for PHPT tests - -## [8.5.11] - 2020-11-27 - -### Changed - -* Bumped required version of `phpunit/php-code-coverage` - -## [8.5.10] - 2020-11-27 - -### Added - -* Support for Xdebug 3 - -### Fixed - -* [#4516](https://github.com/sebastianbergmann/phpunit/issues/4516): `phpunit/phpunit-selenium` does not work with PHPUnit 8.5.9 - -## [8.5.9] - 2020-11-10 - -### Fixed - -* [#3965](https://github.com/sebastianbergmann/phpunit/issues/3965): Process Isolation throws exceptions when PHPDBG is used -* [#4470](https://github.com/sebastianbergmann/phpunit/pull/4470): Infinite recursion when `--static-backup --strict-global-state` is used - -## [8.5.8] - 2020-06-22 - -### Fixed - -* [#4312](https://github.com/sebastianbergmann/phpunit/issues/4312): Fix for [#4299](https://github.com/sebastianbergmann/phpunit/issues/4299) breaks backward compatibility - -## [8.5.7] - 2020-06-21 - -### Fixed - -* [#4299](https://github.com/sebastianbergmann/phpunit/issues/4299): "No tests executed" does not always result in exit code `1` -* [#4306](https://github.com/sebastianbergmann/phpunit/issues/4306): Exceptions during code coverage driver initialization are not handled correctly - -## [8.5.6] - 2020-06-15 - -### Fixed - -* [#4211](https://github.com/sebastianbergmann/phpunit/issues/4211): `phpdbg_*()` functions are scoped to `PHPUnit\phpdbg_*()` - -## [8.5.5] - 2020-05-22 - -### Fixed - -* [#4033](https://github.com/sebastianbergmann/phpunit/issues/4033): Unexpected behaviour when `$GLOBALS` is deleted - -## [8.5.4] - 2020-04-23 - -### Changed - -* Changed how `PHPUnit\TextUI\Command` passes warnings to `PHPUnit\TextUI\TestRunner` - -## [8.5.3] - 2020-03-31 - -### Fixed - -* [#4017](https://github.com/sebastianbergmann/phpunit/issues/4017): Do not suggest refactoring to something that is also deprecated -* [#4133](https://github.com/sebastianbergmann/phpunit/issues/4133): `expectExceptionMessageRegExp()` has been removed in PHPUnit 9 without a deprecation warning being given in PHPUnit 8 -* [#4139](https://github.com/sebastianbergmann/phpunit/issues/4139): Cannot double interfaces that declare a constructor with PHP 8 -* [#4144](https://github.com/sebastianbergmann/phpunit/issues/4144): Empty objects are converted to empty arrays in JSON comparison failure diff - -## [8.5.2] - 2020-01-08 - -### Removed - -* `eval-stdin.php` has been removed, it was not used anymore since PHPUnit 7.2.7 - -## [8.5.1] - 2019-12-25 - -### Changed - -* `eval-stdin.php` can now only be executed with `cli` and `phpdbg` - -### Fixed - -* [#3983](https://github.com/sebastianbergmann/phpunit/issues/3983): Deprecation warning given too eagerly - -## [8.5.0] - 2019-12-06 - -### Added - -* [#3911](https://github.com/sebastianbergmann/phpunit/issues/3911): Support combined use of `addMethods()` and `onlyMethods()` -* [#3949](https://github.com/sebastianbergmann/phpunit/issues/3949): Introduce specialized assertions `assertFileEqualsCanonicalizing()`, `assertFileEqualsIgnoringCase()`, `assertStringEqualsFileCanonicalizing()`, `assertStringEqualsFileIgnoringCase()`, `assertFileNotEqualsCanonicalizing()`, `assertFileNotEqualsIgnoringCase()`, `assertStringNotEqualsFileCanonicalizing()`, and `assertStringNotEqualsFileIgnoringCase()` as alternative to using `assertFileEquals()` etc. with optional parameters - -### Changed - -* [#3860](https://github.com/sebastianbergmann/phpunit/pull/3860): Deprecate invoking PHPUnit commandline test runner with just a class name -* [#3950](https://github.com/sebastianbergmann/phpunit/issues/3950): Deprecate optional parameters of `assertFileEquals()` etc. -* [#3955](https://github.com/sebastianbergmann/phpunit/issues/3955): Deprecate support for doubling multiple interfaces - -### Fixed - -* [#3953](https://github.com/sebastianbergmann/phpunit/issues/3953): Code Coverage for test executed in isolation does not work when the PHAR is used -* [#3967](https://github.com/sebastianbergmann/phpunit/issues/3967): Cannot double interface that extends interface that extends `\Throwable` -* [#3968](https://github.com/sebastianbergmann/phpunit/pull/3968): Test class run in a separate PHP process are passing when `exit` called inside - -[8.5.33]: https://github.com/sebastianbergmann/phpunit/compare/8.5.32...8.5.33 -[8.5.32]: https://github.com/sebastianbergmann/phpunit/compare/8.5.31...8.5.32 -[8.5.31]: https://github.com/sebastianbergmann/phpunit/compare/8.5.30...8.5.31 -[8.5.30]: https://github.com/sebastianbergmann/phpunit/compare/8.5.29...8.5.30 -[8.5.29]: https://github.com/sebastianbergmann/phpunit/compare/8.5.28...8.5.29 -[8.5.28]: https://github.com/sebastianbergmann/phpunit/compare/8.5.27...8.5.28 -[8.5.27]: https://github.com/sebastianbergmann/phpunit/compare/8.5.26...8.5.27 -[8.5.26]: https://github.com/sebastianbergmann/phpunit/compare/8.5.25...8.5.26 -[8.5.25]: https://github.com/sebastianbergmann/phpunit/compare/8.5.24...8.5.25 -[8.5.24]: https://github.com/sebastianbergmann/phpunit/compare/8.5.23...8.5.24 -[8.5.23]: https://github.com/sebastianbergmann/phpunit/compare/8.5.22...8.5.23 -[8.5.22]: https://github.com/sebastianbergmann/phpunit/compare/8.5.21...8.5.22 -[8.5.21]: https://github.com/sebastianbergmann/phpunit/compare/8.5.20...8.5.21 -[8.5.20]: https://github.com/sebastianbergmann/phpunit/compare/8.5.19...8.5.20 -[8.5.19]: https://github.com/sebastianbergmann/phpunit/compare/8.5.18...8.5.19 -[8.5.18]: https://github.com/sebastianbergmann/phpunit/compare/8.5.17...8.5.18 -[8.5.17]: https://github.com/sebastianbergmann/phpunit/compare/8.5.16...8.5.17 -[8.5.16]: https://github.com/sebastianbergmann/phpunit/compare/8.5.15...8.5.16 -[8.5.15]: https://github.com/sebastianbergmann/phpunit/compare/8.5.14...8.5.15 -[8.5.14]: https://github.com/sebastianbergmann/phpunit/compare/8.5.13...8.5.14 -[8.5.13]: https://github.com/sebastianbergmann/phpunit/compare/8.5.12...8.5.13 -[8.5.12]: https://github.com/sebastianbergmann/phpunit/compare/8.5.11...8.5.12 -[8.5.11]: https://github.com/sebastianbergmann/phpunit/compare/8.5.10...8.5.11 -[8.5.10]: https://github.com/sebastianbergmann/phpunit/compare/8.5.9...8.5.10 -[8.5.9]: https://github.com/sebastianbergmann/phpunit/compare/8.5.8...8.5.9 -[8.5.8]: https://github.com/sebastianbergmann/phpunit/compare/8.5.7...8.5.8 -[8.5.7]: https://github.com/sebastianbergmann/phpunit/compare/8.5.6...8.5.7 -[8.5.6]: https://github.com/sebastianbergmann/phpunit/compare/8.5.5...8.5.6 -[8.5.5]: https://github.com/sebastianbergmann/phpunit/compare/8.5.4...8.5.5 -[8.5.4]: https://github.com/sebastianbergmann/phpunit/compare/8.5.3...8.5.4 -[8.5.3]: https://github.com/sebastianbergmann/phpunit/compare/8.5.2...8.5.3 -[8.5.2]: https://github.com/sebastianbergmann/phpunit/compare/8.5.1...8.5.2 -[8.5.1]: https://github.com/sebastianbergmann/phpunit/compare/8.5.0...8.5.1 -[8.5.0]: https://github.com/sebastianbergmann/phpunit/compare/8.4.3...8.5.0 diff --git a/www/vendor/phpunit/phpunit/ChangeLog-9.6.md b/www/vendor/phpunit/phpunit/ChangeLog-9.6.md index df27bce7..5995d581 100644 --- a/www/vendor/phpunit/phpunit/ChangeLog-9.6.md +++ b/www/vendor/phpunit/phpunit/ChangeLog-9.6.md @@ -2,6 +2,34 @@ All notable changes of the PHPUnit 9.6 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. +## [9.6.8] - 2023-05-11 + +### Fixed + +* [#5345](https://github.com/sebastianbergmann/phpunit/issues/5345): No stack trace shown for previous exceptions during bootstrap + +## [9.6.7] - 2023-04-14 + +### Fixed + +* Tests that have `@doesNotPerformAssertions` do not contribute to code coverage + +## [9.6.6] - 2023-03-27 + +### Fixed + +* [#5270](https://github.com/sebastianbergmann/phpunit/issues/5270): `GlobalState::getIniSettingsAsString()` generates code that triggers warnings + +## [9.6.5] - 2023-03-09 + +### Changed + +* Backported the HTML and CSS improvements made to the `--testdox-html` from PHPUnit 10 + +### Fixed + +* [#5205](https://github.com/sebastianbergmann/phpunit/issues/5205): Wrong default value for optional parameter of `PHPUnit\Util\Test::parseTestMethodAnnotations()` causes `ReflectionException` + ## [9.6.4] - 2023-02-27 ### Fixed @@ -36,6 +64,10 @@ All notable changes of the PHPUnit 9.6 release series are documented in this fil * [#5064](https://github.com/sebastianbergmann/phpunit/issues/5064): Deprecate `PHPUnit\Framework\TestCase::getMockClass()` * [#5132](https://github.com/sebastianbergmann/phpunit/issues/5132): Deprecate `Test` suffix for abstract test case classes +[9.6.8]: https://github.com/sebastianbergmann/phpunit/compare/9.6.7...9.6.8 +[9.6.7]: https://github.com/sebastianbergmann/phpunit/compare/9.6.6...9.6.7 +[9.6.6]: https://github.com/sebastianbergmann/phpunit/compare/9.6.5...9.6.6 +[9.6.5]: https://github.com/sebastianbergmann/phpunit/compare/9.6.4...9.6.5 [9.6.4]: https://github.com/sebastianbergmann/phpunit/compare/9.6.3...9.6.4 [9.6.3]: https://github.com/sebastianbergmann/phpunit/compare/9.6.2...9.6.3 [9.6.2]: https://github.com/sebastianbergmann/phpunit/compare/9.6.1...9.6.2 diff --git a/www/vendor/phpunit/phpunit/composer.json b/www/vendor/phpunit/phpunit/composer.json index 38117ea1..28411d9b 100644 --- a/www/vendor/phpunit/phpunit/composer.json +++ b/www/vendor/phpunit/phpunit/composer.json @@ -17,7 +17,8 @@ } ], "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues" + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy" }, "prefer-stable": true, "require": { @@ -57,8 +58,8 @@ "sort-packages": true }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" diff --git a/www/vendor/phpunit/phpunit/phpunit b/www/vendor/phpunit/phpunit/phpunit index c8029566..b9f5cf29 100755 --- a/www/vendor/phpunit/phpunit/phpunit +++ b/www/vendor/phpunit/phpunit/phpunit @@ -38,22 +38,31 @@ if (version_compare('7.3.0', PHP_VERSION, '>')) { die(1); } -foreach (['dom', 'json', 'libxml', 'mbstring', 'tokenizer', 'xml', 'xmlwriter'] as $extension) { - if (extension_loaded($extension)) { - continue; - } +$requiredExtensions = ['dom', 'json', 'libxml', 'mbstring', 'tokenizer', 'xml', 'xmlwriter']; +$unavailableExtensions = array_filter( + $requiredExtensions, + static function ($extension) { + return !extension_loaded($extension); + } +); + +if ([] !== $unavailableExtensions) { fwrite( STDERR, sprintf( - 'PHPUnit requires the "%s" extension.' . PHP_EOL, - $extension + 'PHPUnit requires the "%s" extensions, but the "%s" %s not available.' . PHP_EOL, + implode('", "', $requiredExtensions), + implode('", "', $unavailableExtensions), + count($unavailableExtensions) === 1 ? 'extension is' : 'extensions are' ) ); die(1); } +unset($requiredExtensions, $unavailableExtensions); + if (!ini_get('date.timezone')) { ini_set('date.timezone', 'UTC'); } diff --git a/www/vendor/phpunit/phpunit/src/Framework/Assert.php b/www/vendor/phpunit/phpunit/src/Framework/Assert.php index 156220a5..9872b25c 100644 --- a/www/vendor/phpunit/phpunit/src/Framework/Assert.php +++ b/www/vendor/phpunit/phpunit/src/Framework/Assert.php @@ -1304,7 +1304,7 @@ abstract class Assert */ public static function assertObjectHasAttribute(string $attributeName, $object, string $message = ''): void { - self::createWarning('assertObjectHasAttribute() is deprecated and will be removed in PHPUnit 10.'); + self::createWarning('assertObjectHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectHasProperty() (PHPUnit 10.1.0+) instead.'); if (!self::isValidObjectAttributeName($attributeName)) { throw InvalidArgumentException::create(1, 'valid attribute name'); @@ -1334,7 +1334,7 @@ abstract class Assert */ public static function assertObjectNotHasAttribute(string $attributeName, $object, string $message = ''): void { - self::createWarning('assertObjectNotHasAttribute() is deprecated and will be removed in PHPUnit 10.'); + self::createWarning('assertObjectNotHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectNotHasProperty() (PHPUnit 10.1.0+) instead.'); if (!self::isValidObjectAttributeName($attributeName)) { throw InvalidArgumentException::create(1, 'valid attribute name'); diff --git a/www/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php b/www/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php index 0370b511..4f106b1e 100644 --- a/www/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php +++ b/www/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php @@ -92,7 +92,7 @@ final class IsEqualWithDelta extends Constraint public function toString(): string { return sprintf( - 'is equal to %s with delta <%F>>', + 'is equal to %s with delta <%F>', $this->exporter()->export($this->value), $this->delta ); diff --git a/www/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php b/www/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php index 17e3312c..4810ecae 100644 --- a/www/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php +++ b/www/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php @@ -72,7 +72,6 @@ trait MockedCloneMethodWithVoidReturnType } } EOT; - private const MOCKED_CLONE_METHOD_WITHOUT_RETURN_TYPE_TRAIT = <<<'EOT' namespace PHPUnit\Framework\MockObject; @@ -84,7 +83,6 @@ trait MockedCloneMethodWithoutReturnType } } EOT; - private const UNMOCKED_CLONE_METHOD_WITH_VOID_RETURN_TYPE_TRAIT = <<<'EOT' namespace PHPUnit\Framework\MockObject; @@ -98,7 +96,6 @@ trait UnmockedCloneMethodWithVoidReturnType } } EOT; - private const UNMOCKED_CLONE_METHOD_WITHOUT_RETURN_TYPE_TRAIT = <<<'EOT' namespace PHPUnit\Framework\MockObject; diff --git a/www/vendor/phpunit/phpunit/src/Framework/TestResult.php b/www/vendor/phpunit/phpunit/src/Framework/TestResult.php index 4fde29fa..22150a5a 100644 --- a/www/vendor/phpunit/phpunit/src/Framework/TestResult.php +++ b/www/vendor/phpunit/phpunit/src/Framework/TestResult.php @@ -804,6 +804,7 @@ final class TestResult implements Countable } if ($this->beStrictAboutTestsThatDoNotTestAnything && + !$test->doesNotPerformAssertions() && $test->getNumAssertions() === 0) { $risky = true; } diff --git a/www/vendor/phpunit/phpunit/src/Runner/Version.php b/www/vendor/phpunit/phpunit/src/Runner/Version.php index 7fda90ba..268045a4 100644 --- a/www/vendor/phpunit/phpunit/src/Runner/Version.php +++ b/www/vendor/phpunit/phpunit/src/Runner/Version.php @@ -41,7 +41,7 @@ final class Version } if (self::$version === '') { - self::$version = (new VersionId('9.6.4', dirname(__DIR__, 2)))->getVersion(); + self::$version = (new VersionId('9.6.8', dirname(__DIR__, 2)))->getVersion(); } return self::$version; diff --git a/www/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php b/www/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php index 9030b1db..da488082 100644 --- a/www/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php +++ b/www/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php @@ -121,7 +121,6 @@ final class Builder 'whitelist=', 'dump-xdebug-filter=', ]; - private const SHORT_OPTIONS = 'd:c:hv'; public function fromParameters(array $parameters, array $additionalLongOptions): Configuration diff --git a/www/vendor/phpunit/phpunit/src/TextUI/Command.php b/www/vendor/phpunit/phpunit/src/TextUI/Command.php index 48243caa..0bebad6a 100644 --- a/www/vendor/phpunit/phpunit/src/TextUI/Command.php +++ b/www/vendor/phpunit/phpunit/src/TextUI/Command.php @@ -568,16 +568,29 @@ class Command $this->exitWithErrorMessage($t->getMessage()); } - $this->exitWithErrorMessage( - sprintf( - 'Error in bootstrap script: %s:%s%s%s%s', + $message = sprintf( + 'Error in bootstrap script: %s:%s%s%s%s', + get_class($t), + PHP_EOL, + $t->getMessage(), + PHP_EOL, + $t->getTraceAsString() + ); + + while ($t = $t->getPrevious()) { + $message .= sprintf( + '%s%sPrevious error: %s:%s%s%s%s', + PHP_EOL, + PHP_EOL, get_class($t), PHP_EOL, $t->getMessage(), PHP_EOL, - $t->getTraceAsString() - ) - ); + $t->getTraceAsString(), + ); + } + + $this->exitWithErrorMessage($message); } } diff --git a/www/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php b/www/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php index 99f0fa9d..408fa133 100644 --- a/www/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php +++ b/www/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php @@ -47,23 +47,15 @@ use Throwable; */ class DefaultResultPrinter extends Printer implements ResultPrinter { - public const EVENT_TEST_START = 0; - - public const EVENT_TEST_END = 1; - + public const EVENT_TEST_START = 0; + public const EVENT_TEST_END = 1; public const EVENT_TESTSUITE_START = 2; - - public const EVENT_TESTSUITE_END = 3; - - public const COLOR_NEVER = 'never'; - - public const COLOR_AUTO = 'auto'; - - public const COLOR_ALWAYS = 'always'; - - public const COLOR_DEFAULT = self::COLOR_NEVER; - - private const AVAILABLE_COLORS = [self::COLOR_NEVER, self::COLOR_AUTO, self::COLOR_ALWAYS]; + public const EVENT_TESTSUITE_END = 3; + public const COLOR_NEVER = 'never'; + public const COLOR_AUTO = 'auto'; + public const COLOR_ALWAYS = 'always'; + public const COLOR_DEFAULT = self::COLOR_NEVER; + private const AVAILABLE_COLORS = [self::COLOR_NEVER, self::COLOR_AUTO, self::COLOR_ALWAYS]; /** * @var int diff --git a/www/vendor/phpunit/phpunit/src/TextUI/Help.php b/www/vendor/phpunit/phpunit/src/TextUI/Help.php index 084f2a21..82f305dd 100644 --- a/www/vendor/phpunit/phpunit/src/TextUI/Help.php +++ b/www/vendor/phpunit/phpunit/src/TextUI/Help.php @@ -27,8 +27,7 @@ use SebastianBergmann\Environment\Console; final class Help { private const LEFT_MARGIN = ' '; - - private const HELP_TEXT = [ + private const HELP_TEXT = [ 'Usage' => [ ['text' => 'phpunit [options] UnitTest.php'], ['text' => 'phpunit [options] '], diff --git a/www/vendor/phpunit/phpunit/src/TextUI/TestRunner.php b/www/vendor/phpunit/phpunit/src/TextUI/TestRunner.php index c1362f3a..3ba298e8 100644 --- a/www/vendor/phpunit/phpunit/src/TextUI/TestRunner.php +++ b/www/vendor/phpunit/phpunit/src/TextUI/TestRunner.php @@ -88,10 +88,8 @@ use SebastianBergmann\Timer\Timer; */ final class TestRunner extends BaseTestRunner { - public const SUCCESS_EXIT = 0; - - public const FAILURE_EXIT = 1; - + public const SUCCESS_EXIT = 0; + public const FAILURE_EXIT = 1; public const EXCEPTION_EXIT = 2; /** diff --git a/www/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php b/www/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php index 648f9edc..5066c4bb 100644 --- a/www/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php +++ b/www/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php @@ -67,17 +67,12 @@ final class DocBlock */ public const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/'; - private const REGEX_REQUIRES_VERSION = '/@requires\s+(?PPHP(?:Unit)?)\s+(?P[<>=!]{0,2})\s*(?P[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m'; - + private const REGEX_REQUIRES_VERSION = '/@requires\s+(?PPHP(?:Unit)?)\s+(?P[<>=!]{0,2})\s*(?P[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m'; private const REGEX_REQUIRES_VERSION_CONSTRAINT = '/@requires\s+(?PPHP(?:Unit)?)\s+(?P[\d\t \-.|~^]+)[ \t]*\r?$/m'; - - private const REGEX_REQUIRES_OS = '/@requires\s+(?POS(?:FAMILY)?)\s+(?P.+?)[ \t]*\r?$/m'; - - private const REGEX_REQUIRES_SETTING = '/@requires\s+(?Psetting)\s+(?P([^ ]+?))\s*(?P[\w\.-]+[\w\.]?)?[ \t]*\r?$/m'; - - private const REGEX_REQUIRES = '/@requires\s+(?Pfunction|extension)\s+(?P([^\s<>=!]+))\s*(?P[<>=!]{0,2})\s*(?P[\d\.-]+[\d\.]?)?[ \t]*\r?$/m'; - - private const REGEX_TEST_WITH = '/@testWith\s+/'; + private const REGEX_REQUIRES_OS = '/@requires\s+(?POS(?:FAMILY)?)\s+(?P.+?)[ \t]*\r?$/m'; + private const REGEX_REQUIRES_SETTING = '/@requires\s+(?Psetting)\s+(?P([^ ]+?))\s*(?P[\w\.-]+[\w\.]?)?[ \t]*\r?$/m'; + private const REGEX_REQUIRES = '/@requires\s+(?Pfunction|extension)\s+(?P([^\s<>=!]+))\s*(?P[<>=!]{0,2})\s*(?P[\d\.-]+[\d\.]?)?[ \t]*\r?$/m'; + private const REGEX_TEST_WITH = '/@testWith\s+/'; /** @var string */ private $docComment; diff --git a/www/vendor/phpunit/phpunit/src/Util/GlobalState.php b/www/vendor/phpunit/phpunit/src/Util/GlobalState.php index cc5c2228..5cf16bcd 100644 --- a/www/vendor/phpunit/phpunit/src/Util/GlobalState.php +++ b/www/vendor/phpunit/phpunit/src/Util/GlobalState.php @@ -9,6 +9,8 @@ */ namespace PHPUnit\Util; +use const PHP_MAJOR_VERSION; +use const PHP_MINOR_VERSION; use function array_keys; use function array_reverse; use function array_shift; @@ -47,6 +49,79 @@ final class GlobalState '_REQUEST', ]; + /** + * @psalm-var array> + */ + private const DEPRECATED_INI_SETTINGS = [ + '7.3' => [ + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.func_overload' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'string.strip_tags' => true, + ], + + '7.4' => [ + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.func_overload' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'pdo_odbc.db2_instance_name' => true, + 'string.strip_tags' => true, + ], + + '8.0' => [ + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + ], + + '8.1' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + + '8.2' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + + '8.3' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + ]; + /** * @throws Exception */ @@ -106,6 +181,10 @@ final class GlobalState $result = ''; foreach (ini_get_all(null, false) as $key => $value) { + if (self::isIniSettingDeprecated($key)) { + continue; + } + $result .= sprintf( '@ini_set(%s, %s);' . "\n", self::exportVariable($key), @@ -200,4 +279,9 @@ final class GlobalState return $result; } + + private static function isIniSettingDeprecated(string $iniSetting): bool + { + return isset(self::DEPRECATED_INI_SETTINGS[PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION][$iniSetting]); + } } diff --git a/www/vendor/phpunit/phpunit/src/Util/Test.php b/www/vendor/phpunit/phpunit/src/Util/Test.php index f089f6d4..d04a7683 100644 --- a/www/vendor/phpunit/phpunit/src/Util/Test.php +++ b/www/vendor/phpunit/phpunit/src/Util/Test.php @@ -331,7 +331,7 @@ final class Test /** * @psalm-param class-string $className */ - public static function parseTestMethodAnnotations(string $className, ?string $methodName = ''): array + public static function parseTestMethodAnnotations(string $className, ?string $methodName = null): array { $registry = Registry::getInstance(); diff --git a/www/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php b/www/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php index def16c39..b66eb8b9 100644 --- a/www/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php +++ b/www/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php @@ -66,7 +66,6 @@ class CliTestDoxPrinter extends TestDoxPrinter " \e[36m◑\e[0m running tests", " \e[36m◒\e[0m running tests", ]; - private const STATUS_STYLES = [ BaseTestRunner::STATUS_PASSED => [ 'symbol' => '✔', diff --git a/www/vendor/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.php b/www/vendor/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.php index 013d1de8..776a83bd 100644 --- a/www/vendor/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.php +++ b/www/vendor/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.php @@ -29,26 +29,47 @@ final class HtmlResultPrinter extends ResultPrinter @@ -60,7 +81,7 @@ EOT; */ private const CLASS_HEADER = <<<'EOT' -

%s

+

%s

    EOT; @@ -101,7 +122,6 @@ EOT; $this->write( sprintf( self::CLASS_HEADER, - $name, $this->currentTestClassPrettified ) ); @@ -114,9 +134,8 @@ EOT; { $this->write( sprintf( - "
  • %s %s
  • \n", - $success ? '#555753' : '#ef2929', - $success ? '✓' : '❌', + "
  • %s
  • \n", + $success ? 'success' : 'defect', $name ) ); diff --git a/www/vendor/psr/log/LICENSE b/www/vendor/psr/log/LICENSE new file mode 100644 index 00000000..474c952b --- /dev/null +++ b/www/vendor/psr/log/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 PHP Framework Interoperability Group + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/www/vendor/psr/log/README.md b/www/vendor/psr/log/README.md new file mode 100644 index 00000000..a9f20c43 --- /dev/null +++ b/www/vendor/psr/log/README.md @@ -0,0 +1,58 @@ +PSR Log +======= + +This repository holds all interfaces/classes/traits related to +[PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md). + +Note that this is not a logger of its own. It is merely an interface that +describes a logger. See the specification for more details. + +Installation +------------ + +```bash +composer require psr/log +``` + +Usage +----- + +If you need a logger, you can use the interface like this: + +```php +logger = $logger; + } + + public function doSomething() + { + if ($this->logger) { + $this->logger->info('Doing work'); + } + + try { + $this->doSomethingElse(); + } catch (Exception $exception) { + $this->logger->error('Oh no!', array('exception' => $exception)); + } + + // do something useful + } +} +``` + +You can then pick one of the implementations of the interface to get a logger. + +If you want to implement the interface, you can require this package and +implement `Psr\Log\LoggerInterface` in your code. Please read the +[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +for details. diff --git a/www/vendor/psr/log/composer.json b/www/vendor/psr/log/composer.json new file mode 100644 index 00000000..879fc6f5 --- /dev/null +++ b/www/vendor/psr/log/composer.json @@ -0,0 +1,26 @@ +{ + "name": "psr/log", + "description": "Common interface for logging libraries", + "keywords": ["psr", "psr-3", "log"], + "homepage": "https://github.com/php-fig/log", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=8.0.0" + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + } +} diff --git a/www/vendor/psr/log/src/AbstractLogger.php b/www/vendor/psr/log/src/AbstractLogger.php new file mode 100644 index 00000000..d60a091a --- /dev/null +++ b/www/vendor/psr/log/src/AbstractLogger.php @@ -0,0 +1,15 @@ +logger = $logger; + } +} diff --git a/www/vendor/psr/log/src/LoggerInterface.php b/www/vendor/psr/log/src/LoggerInterface.php new file mode 100644 index 00000000..b3a24b5f --- /dev/null +++ b/www/vendor/psr/log/src/LoggerInterface.php @@ -0,0 +1,125 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function alert(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function critical(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function error(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function warning(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function notice(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function info(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string|\Stringable $message + * @param array $context + * + * @return void + */ + public function debug(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::DEBUG, $message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string|\Stringable $message + * @param array $context + * + * @return void + * + * @throws \Psr\Log\InvalidArgumentException + */ + abstract public function log($level, string|\Stringable $message, array $context = []): void; +} diff --git a/www/vendor/psr/log/src/NullLogger.php b/www/vendor/psr/log/src/NullLogger.php new file mode 100644 index 00000000..c1cc3c06 --- /dev/null +++ b/www/vendor/psr/log/src/NullLogger.php @@ -0,0 +1,30 @@ +logger) { }` + * blocks. + */ +class NullLogger extends AbstractLogger +{ + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string|\Stringable $message + * @param array $context + * + * @return void + * + * @throws \Psr\Log\InvalidArgumentException + */ + public function log($level, string|\Stringable $message, array $context = []): void + { + // noop + } +} diff --git a/www/vendor/sebastian/diff/ChangeLog.md b/www/vendor/sebastian/diff/ChangeLog.md index 9bdcc5b6..a6ccfad7 100644 --- a/www/vendor/sebastian/diff/ChangeLog.md +++ b/www/vendor/sebastian/diff/ChangeLog.md @@ -2,6 +2,13 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. +## [4.0.5] - 2023-05-07 + +### Changed + +* [#118](https://github.com/sebastianbergmann/diff/pull/118): Improve performance of `MemoryEfficientLongestCommonSubsequenceCalculator` +* [#119](https://github.com/sebastianbergmann/diff/pull/119): Improve performance of `TimeEfficientLongestCommonSubsequenceCalculator` + ## [4.0.4] - 2020-10-26 ### Fixed @@ -76,6 +83,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt * This component is no longer supported on PHP 5.6 +[4.0.5]: https://github.com/sebastianbergmann/diff/compare/4.0.4...4.0.5 [4.0.4]: https://github.com/sebastianbergmann/diff/compare/4.0.3...4.0.4 [4.0.3]: https://github.com/sebastianbergmann/diff/compare/4.0.2...4.0.3 [4.0.2]: https://github.com/sebastianbergmann/diff/compare/4.0.1...4.0.2 diff --git a/www/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php b/www/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php index 0b626eaf..489113b6 100644 --- a/www/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php +++ b/www/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php @@ -78,7 +78,12 @@ final class MemoryEfficientLongestCommonSubsequenceCalculator implements Longest if ($from[$i] === $to[$j]) { $current[$j + 1] = $prev[$j] + 1; } else { - $current[$j + 1] = max($current[$j], $prev[$j + 1]); + // don't use max() to avoid function call overhead + if ($current[$j] > $prev[$j + 1]) { + $current[$j + 1] = $current[$j]; + } else { + $current[$j + 1] = $prev[$j + 1]; + } } } } diff --git a/www/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php b/www/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php index fd19cac7..4e8d951d 100644 --- a/www/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php +++ b/www/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php @@ -37,12 +37,24 @@ final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCo for ($i = 1; $i <= $fromLength; ++$i) { for ($j = 1; $j <= $toLength; ++$j) { - $o = ($j * $width) + $i; - $matrix[$o] = max( - $matrix[$o - 1], - $matrix[$o - $width], - $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0 - ); + $o = ($j * $width) + $i; + + // don't use max() to avoid function call overhead + $firstOrLast = $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0; + + if ($matrix[$o - 1] > $matrix[$o - $width]) { + if ($firstOrLast > $matrix[$o - 1]) { + $matrix[$o] = $firstOrLast; + } else { + $matrix[$o] = $matrix[$o - 1]; + } + } else { + if ($firstOrLast > $matrix[$o - $width]) { + $matrix[$o] = $firstOrLast; + } else { + $matrix[$o] = $matrix[$o - $width]; + } + } } }