diff --git a/docs/checkers_doc.md b/docs/checkers_doc.md index 1c28d347..b7f9f0e3 100644 --- a/docs/checkers_doc.md +++ b/docs/checkers_doc.md @@ -113,7 +113,6 @@ - [`arrayAccess` checker](#arrayaccess-checker) - [`classMembersOrder` checker](#classmembersorder-checker) - [`complexity` checker](#complexity-checker) - - [`deprecatedUntagged` checker](#deprecateduntagged-checker) - [`errorSilence` checker](#errorsilence-checker) - [`getTypeMisUse` checker (autofixable)](#gettypemisuse-checker) - [`langDeprecated` checker](#langdeprecated-checker) @@ -2303,34 +2302,6 @@ function checkRights() {


-### `deprecatedUntagged` checker - -#### Description - -Report usages of deprecated symbols if the `@deprecated` tag has no description (see `deprecated` check). - -#### Non-compliant code: -```php -/** - * @deprecated - */ -function f() {} - -f(); -``` - -#### Compliant code: -```php -/** - * @deprecated - */ -function f() {} - -g(); -``` -


- - ### `errorSilence` checker #### Description diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 66cd5c13..ace77db1 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -253,13 +253,6 @@ func (b *blockLinter) checkClass(class *ir.ClassStmt) { case *ir.ClassMethodStmt: members = append(members, classMethod) b.walker.CheckParamNullability(value.Params) - case *ir.PropertyListStmt: - for _, element := range value.Doc.Parsed { - if element.Name() == "deprecated" { - b.report(stmt, LevelNotice, "deprecated", "Has deprecated field in class %s", class.ClassName.Value) - } - } - members = append(members, classOtherMember) default: members = append(members, classOtherMember) } @@ -565,6 +558,15 @@ func (b *blockLinter) checkNew(e *ir.NewExpr) { if class.IsInterface() { b.report(e.Class, LevelError, "invalidNew", "Cannot instantiate interface %s", class.Name) } + + if class.IsDeprecated() { + if class.WithDeprecationNote() { + b.report(e, LevelNotice, "deprecated", "Try to create instance of the class %s that was marked as deprecated (%s)", class.Name, class.DeprecationInfo) + } else { + b.report(e, LevelNotice, "deprecated", "Try to create instance %s class that was marked as deprecated", class.Name) + } + } + b.walker.r.checker.CheckNameCase(e.Class, className, class.Name) } @@ -1035,7 +1037,7 @@ func (b *blockLinter) checkDeprecatedFunctionCall(e *ir.FunctionCallExpr, call * return } - b.report(e.Function, LevelNotice, "deprecatedUntagged", "Call to deprecated function %s", utils.NameNodeToString(e.Function)) + b.report(e.Function, LevelNotice, "deprecated", "Call to deprecated function %s", utils.NameNodeToString(e.Function)) } func (b *blockLinter) checkFunctionAvailability(e *ir.FunctionCallExpr, call *funcCallInfo) { @@ -1387,7 +1389,7 @@ func (b *blockLinter) checkMethodCall(e *ir.MethodCallExpr) { b.report(e.Method, LevelNotice, "deprecated", "Call to deprecated method {%s}->%s() (%s)", call.methodCallerType, call.methodName, deprecation) } else { - b.report(e.Method, LevelNotice, "deprecatedUntagged", "Call to deprecated method {%s}->%s()", + b.report(e.Method, LevelNotice, "deprecated", "Call to deprecated method {%s}->%s()", call.methodCallerType, call.methodName) } } @@ -1465,7 +1467,7 @@ func (b *blockLinter) checkStaticCall(e *ir.StaticCallExpr) { b.report(e.Call, LevelNotice, "deprecated", "Call to deprecated static method %s::%s() (%s)", call.className, call.methodName, deprecation) } else { - b.report(e.Call, LevelNotice, "deprecatedUntagged", "Call to deprecated static method %s::%s()", + b.report(e.Call, LevelNotice, "deprecated", "Call to deprecated static method %s::%s()", call.className, call.methodName) } } @@ -1524,6 +1526,14 @@ func (b *blockLinter) checkPropertyFetch(e *ir.PropertyFetchExpr) { b.report(e.Property, LevelError, "accessLevel", "Cannot access %s property %s->%s", fetch.info.AccessLevel, fetch.className, fetch.propertyNode.Value) } + if fetch.info.IsDeprecated() { + if fetch.info.WithDeprecationNote() { + b.report(e, LevelNotice, "deprecated", "Try to call property %s that was marked as deprecated (%s) in the class %s", fetch.propertyNode.Value, fetch.info.DeprecationInfo, fetch.className) + } else { + b.report(e, LevelNotice, "deprecated", "Try to call property %s that was marked as deprecated in the class %s", fetch.propertyNode.Value, fetch.className) + } + } + left, ok := b.walker.ctx.sc.GetVarType(e.Variable) if ok { b.checkSafetyCall(e, left, "", "PropertyFetch") @@ -1577,6 +1587,14 @@ func (b *blockLinter) checkClassConstFetch(e *ir.ClassConstFetchExpr) { if fetch.isFound && !canAccess(b.classParseState(), fetch.implClassName, fetch.info.AccessLevel) { b.report(e.ConstantName, LevelError, "accessLevel", "Cannot access %s constant %s::%s", fetch.info.AccessLevel, fetch.implClassName, fetch.constName) } + + if fetch.info.IsDeprecated() { + if fetch.info.WithDeprecationNote() { + b.report(e, LevelNotice, "deprecated", "Try to call constant %s that was marked as deprecated (%s) from the class %s", fetch.constName, fetch.info.DeprecationInfo, fetch.className) + } else { + b.report(e, LevelNotice, "deprecated", "Try to call constant %s that was marked as deprecated from the class %s", fetch.constName, fetch.className) + } + } } func (b *blockLinter) checkClassSpecialNameCase(n ir.Node, className string) { diff --git a/src/linter/block_utils.go b/src/linter/block_utils.go index d5580e6f..eca069d5 100644 --- a/src/linter/block_utils.go +++ b/src/linter/block_utils.go @@ -38,10 +38,12 @@ func findProperty(info *meta.Info, className, propName string) (res solver.FindP // Construct a dummy property from the magic method. p.ClassName = m.ClassName p.TraitName = m.TraitName + p.Info = meta.PropertyInfo{ - Pos: m.Info.Pos, - Typ: m.Info.Typ, - AccessLevel: m.Info.AccessLevel, + Pos: m.Info.Pos, + Typ: m.Info.Typ, + AccessLevel: m.Info.AccessLevel, + DeprecationInfo: m.Info.DeprecationInfo, } return p, true, true } diff --git a/src/linter/cache.go b/src/linter/cache.go index bf66e43b..c16c9198 100644 --- a/src/linter/cache.go +++ b/src/linter/cache.go @@ -17,43 +17,44 @@ import ( // // Version log: // -// 27 - added Static field to meta.FuncInfo -// 28 - array type parsed as mixed[] -// 29 - updated type inference for ClassConstFetch -// 30 - resolve ClassConstFetch to a wrapped type string -// 31 - fixed plus operator type inference for arrays -// 32 - replaced Static:bool with Flags:uint8 in meta.FuncInfo -// 33 - support parsing of array and list -// 34 - support parsing of ?ClassName as "ClassName|null" -// 35 - added Flags:uint8 to meta.ClassInfo -// 36 - added FuncAbstract bit to FuncFlags -// added FuncFinal bit to FuncFlags -// added ClassFinal bit to ClassFlags -// FuncInfo now stores original function name -// ClassInfo now stores original class name -// 37 - added ClassShape bit to ClassFlags -// changed meta.scopeVar bool fields representation -// 38 - replaced TypesMap.immutable:bool with flags:uint8. -// added mapPrecise flag to mark precise type maps. -// 39 - added new field Value in ConstantInfo -// 40 - changed string const value storage (no quotes) -// 41 - const-folding affected const definition values -// 42 - bool-typed consts are now stored in meta info -// 43 - define'd const values stored in cache -// 44 - rename ConstantInfo => ConstInfo -// 45 - added Mixins field to meta.ClassInfo -// 46 - changed the way of inferring the return type of functions and methods -// 47 - forced cache version invalidation due to the #921 -// 48 - renamed meta.TypesMap to types.Map; this affects gob encoding -// 49 - for shape, names are now generated using the keys that make up this shape -// 50 - added Flags field for meta.PropertyInfo -// 51 - added anonymous classes -// 52 - renamed all PhpDoc and Phpdoc with PHPDoc -// 53 - added DeprecationInfo for functions and methods and support for some attributes -// 54 - forced cache version invalidation due to the #1165 -// 55 - updated go version 1.16 -> 1.21 -// 56 - added isVariadic to meta.FuncInfo -const cacheVersion = 56 +// 27 - added Static field to meta.FuncInfo +// 28 - array type parsed as mixed[] +// 29 - updated type inference for ClassConstFetch +// 30 - resolve ClassConstFetch to a wrapped type string +// 31 - fixed plus operator type inference for arrays +// 32 - replaced Static:bool with Flags:uint8 in meta.FuncInfo +// 33 - support parsing of array and list +// 34 - support parsing of ?ClassName as "ClassName|null" +// 35 - added Flags:uint8 to meta.ClassInfo +// 36 - added FuncAbstract bit to FuncFlags +// added FuncFinal bit to FuncFlags +// added ClassFinal bit to ClassFlags +// FuncInfo now stores original function name +// ClassInfo now stores original class name +// 37 - added ClassShape bit to ClassFlags +// changed meta.scopeVar bool fields representation +// 38 - replaced TypesMap.immutable:bool with flags:uint8. +// added mapPrecise flag to mark precise type maps. +// 39 - added new field Value in ConstantInfo +// 40 - changed string const value storage (no quotes) +// 41 - const-folding affected const definition values +// 42 - bool-typed consts are now stored in meta info +// 43 - define'd const values stored in cache +// 44 - rename ConstantInfo => ConstInfo +// 45 - added Mixins field to meta.ClassInfo +// 46 - changed the way of inferring the return type of functions and methods +// 47 - forced cache version invalidation due to the #921 +// 48 - renamed meta.TypesMap to types.Map; this affects gob encoding +// 49 - for shape, names are now generated using the keys that make up this shape +// 50 - added Flags field for meta.PropertyInfo +// 51 - added anonymous classes +// 52 - renamed all PhpDoc and Phpdoc with PHPDoc +// 53 - added DeprecationInfo for functions and methods and support for some attributes +// 54 - forced cache version invalidation due to the #1165 +// 55 - updated go version 1.16 -> 1.21 +// 56 - added isVariadic to meta.FuncInfo +// 57 - added DeprecationInfo for property and const +const cacheVersion = 57 var ( errWrongVersion = errors.New("Wrong cache version") diff --git a/src/linter/cache_test.go b/src/linter/cache_test.go index 8281dc48..773966a4 100644 --- a/src/linter/cache_test.go +++ b/src/linter/cache_test.go @@ -149,7 +149,7 @@ main(); // // If cache encoding changes, there is a very high chance that // encoded data lengh will change as well. - wantLen := 5952 + wantLen := 6069 haveLen := buf.Len() if haveLen != wantLen { t.Errorf("cache len mismatch:\nhave: %d\nwant: %d", haveLen, wantLen) @@ -158,7 +158,7 @@ main(); // 2. Check cache "strings" hash. // // It catches new fields in cached types, field renames and encoding of additional named attributes. - wantStrings := "690e77c94ecdd7878de0bf6f6881d786cf1fafa4588f7905f54d700646c4952aad359008ae2dcddb1c7f29163ecee62355d525672090ac30257bc414f690006f" + wantStrings := "339e0a8348fcf8f5060b8ce3534f97be9af03fe462ca06eba27ab83488efc5e5d5813f4fb227535997f0c4a99253f57042876fdead6f058a923219c99593f3b6" haveStrings := collectCacheStrings(buf.String()) if haveStrings != wantStrings { t.Errorf("cache strings mismatch:\nhave: %q\nwant: %q", haveStrings, wantStrings) diff --git a/src/linter/phpdoc_util.go b/src/linter/phpdoc_util.go index 5d794927..51beb21a 100644 --- a/src/linter/phpdoc_util.go +++ b/src/linter/phpdoc_util.go @@ -84,11 +84,16 @@ func (e *PHPDocErrors) pushLint(place PHPDocLocation, format string, args ...int type classPHPDocParseResult struct { properties meta.PropertiesMap methods meta.FunctionsMap + deprecation meta.DeprecationInfo errs PHPDocErrors mixins []string packageName string internal bool - deprecated bool +} + +type variablePHPDocParseResult struct { + typesMap types.Map + deprecation meta.DeprecationInfo } func parseClassPHPDocMethod(classNode ir.Node, ctx *rootContext, result *classPHPDocParseResult, part *phpdoc.RawCommentPart) { diff --git a/src/linter/report.go b/src/linter/report.go index c4c9c62f..0af6f29d 100644 --- a/src/linter/report.go +++ b/src/linter/report.go @@ -743,25 +743,6 @@ f();`, */ function f() {} -g();`, - }, - - { - Name: "deprecatedUntagged", - Default: false, - Quickfix: false, - Comment: "Report usages of deprecated symbols if the `@deprecated` tag has no description (see `deprecated` check).", - Before: `/** - * @deprecated - */ -function f() {} - -f();`, - After: `/** - * @deprecated - */ -function f() {} - g();`, }, diff --git a/src/linter/root.go b/src/linter/root.go index 0fb275f2..4b40ceae 100644 --- a/src/linter/root.go +++ b/src/linter/root.go @@ -201,9 +201,12 @@ func (d *rootWalker) EnterNode(n ir.Node) (res bool) { d.reportPHPDocErrors(doc.errs) d.handleClassDoc(doc, &cl) - if doc.deprecated { - d.Report(n, LevelNotice, "deprecated", "Has deprecated class %s", n.ClassName.Value) + // Handle attributes if any. + deprecation, ok := attributes.Deprecated(n.AttrGroups, d.ctx.st) + if ok { + doc.deprecation.Append(deprecation) } + cl.DeprecationInfo = doc.deprecation d.meta.Classes.Set(d.ctx.st.CurrentClass, cl) @@ -845,7 +848,9 @@ func (d *rootWalker) parseClassPHPDoc(class ir.Node, doc phpdoc.Comment) classPH case "package": parseClassPHPDocPackage(class, d.ctx.st, &result, part.(*phpdoc.PackageCommentPart)) case "deprecated": - result.deprecated = true + part := part.(*phpdoc.RawCommentPart) + result.deprecation.Deprecated = true + result.deprecation.Reason = part.ParamsText case "internal": result.internal = true } @@ -902,19 +907,30 @@ func (d *rootWalker) handleClassDoc(doc classPHPDocParseResult, cl *meta.ClassIn } } -func (d *rootWalker) parsePHPDocVar(doc phpdoc.Comment) (typesMap types.Map) { +func (d *rootWalker) parseVarPHPDoc(doc phpdoc.Comment) variablePHPDocParseResult { + var result variablePHPDocParseResult + + if doc.Raw == "" { + return result + } + for _, part := range doc.Parsed { - part, ok := part.(*phpdoc.TypeVarCommentPart) - if ok && part.Name() == "var" { + switch part.Name() { + case "var": + part := part.(*phpdoc.TypeVarCommentPart) converted := phpdoctypes.ToRealType(d.ctx.typeNormalizer.ClassFQNProvider(), d.config.KPHP, part.Type) moveShapesToContext(&d.ctx, converted.Shapes) d.handleClosuresFromDoc(converted.Closures) - typesMap = types.NewMapWithNormalization(d.ctx.typeNormalizer, converted.Types) + result.typesMap = types.NewMapWithNormalization(d.ctx.typeNormalizer, converted.Types) + case "deprecated": + part := part.(*phpdoc.RawCommentPart) + result.deprecation.Deprecated = true + result.deprecation.Reason = part.ParamsText } } - return typesMap + return result } func (d *rootWalker) enterPropertyList(pl *ir.PropertyListStmt) bool { @@ -936,9 +952,14 @@ func (d *rootWalker) enterPropertyList(pl *ir.PropertyListStmt) bool { } } - phpDocType := d.parsePHPDocVar(pl.Doc) + varPhpDocRes := d.parseVarPHPDoc(pl.Doc) typeHintType, _ := d.parseTypeHintNode(pl.Type) + deprecation, ok := attributes.Deprecated(pl.AttrGroups, d.ctx.st) + if ok { + varPhpDocRes.deprecation.Append(deprecation) + } + for _, pNode := range pl.Properties { prop := pNode.(*ir.PropertyStmt) @@ -947,7 +968,7 @@ func (d *rootWalker) enterPropertyList(pl *ir.PropertyListStmt) bool { // We need to clone the types, because otherwise, if several // properties are written in one definition, and null was // assigned to the first, then all properties become nullable. - propTypes := phpDocType.Clone().Append(typeHintType) + propTypes := varPhpDocRes.typesMap.Clone().Append(typeHintType) if prop.Expr != nil { propTypes = propTypes.Append(solver.ExprTypeLocal(d.scope(), d.ctx.st, prop.Expr)) @@ -959,15 +980,32 @@ func (d *rootWalker) enterPropertyList(pl *ir.PropertyListStmt) bool { // TODO: handle duplicate property cl.Properties[nm] = meta.PropertyInfo{ - Pos: d.getElementPos(prop), - Typ: propTypes.Immutable(), - AccessLevel: accessLevel, + Pos: d.getElementPos(prop), + Typ: propTypes.Immutable(), + AccessLevel: accessLevel, + DeprecationInfo: varPhpDocRes.deprecation, } } return true } +func (d *rootWalker) parseConstPHPDoc(doc phpdoc.Comment) (deprecationInfo meta.DeprecationInfo) { + if doc.Raw == "" { + return deprecationInfo + } + + for _, part := range doc.Parsed { + if part.Name() == "deprecated" { + part := part.(*phpdoc.RawCommentPart) + deprecationInfo.Deprecated = true + deprecationInfo.Reason = part.ParamsText + } + } + + return deprecationInfo +} + func (d *rootWalker) enterClassConstList(list *ir.ClassConstListStmt) bool { cl := d.getClass() accessLevel := meta.Public @@ -984,6 +1022,13 @@ func (d *rootWalker) enterClassConstList(list *ir.ClassConstListStmt) bool { } } + deprecationInfo := d.parseConstPHPDoc(list.Doc) + + deprecation, ok := attributes.Deprecated(list.AttrGroups, d.ctx.st) + if ok { + deprecationInfo.Append(deprecation) + } + for _, cNode := range list.Consts { c := cNode.(*ir.ConstantStmt) @@ -995,10 +1040,11 @@ func (d *rootWalker) enterClassConstList(list *ir.ClassConstListStmt) bool { // TODO: handle duplicate constant cl.Constants[nm] = meta.ConstInfo{ - Pos: d.getElementPos(c), - Typ: typ.Immutable(), - AccessLevel: accessLevel, - Value: value, + Pos: d.getElementPos(c), + Typ: typ.Immutable(), + AccessLevel: accessLevel, + Value: value, + DeprecationInfo: deprecationInfo, } } diff --git a/src/linter/root_checker.go b/src/linter/root_checker.go index f7b12e0d..c3c98522 100644 --- a/src/linter/root_checker.go +++ b/src/linter/root_checker.go @@ -110,13 +110,13 @@ func (r *rootChecker) CheckPropertyList(pl *ir.PropertyListStmt) bool { r.walker.Report(pl, LevelNotice, "implicitModifiers", "Specify the access modifier for %s explicitly", target) } - docblockType := r.walker.parsePHPDocVar(pl.Doc) + varPhpDocRes := r.walker.parseVarPHPDoc(pl.Doc) r.CheckCommentMisspellings(pl, pl.Doc.Raw) - r.CheckPHPDocVar(pl, pl.Doc, docblockType) + r.CheckPHPDocVar(pl, pl.Doc, varPhpDocRes.typesMap) typeHintType, ok := r.walker.parseTypeHintNode(pl.Type) - if ok && !types.TypeHintHasMoreAccurateType(typeHintType, docblockType) { + if ok && !types.TypeHintHasMoreAccurateType(typeHintType, varPhpDocRes.typesMap) { r.walker.Report(pl, LevelNotice, "typeHint", "Specify the type for the property in PHPDoc, 'array' type hint too generic") } @@ -128,7 +128,7 @@ func (r *rootChecker) CheckPropertyList(pl *ir.PropertyListStmt) bool { // We need to clone the types, because otherwise, if several // properties are written in one definition, and null was // assigned to the first, then all properties become nullable. - propTypes := docblockType.Clone().Append(typeHintType) + propTypes := varPhpDocRes.typesMap.Clone().Append(typeHintType) r.CheckAssignNullToNotNullableProperty(prop, propTypes) } diff --git a/src/meta/metainfo.go b/src/meta/metainfo.go index 38f88c00..ea5cf34c 100644 --- a/src/meta/metainfo.go +++ b/src/meta/metainfo.go @@ -178,17 +178,22 @@ type PropertyInfo struct { Typ types.Map AccessLevel AccessLevel Flags PropertyFlags + DeprecationInfo } func (info *PropertyInfo) IsFromAnnotation() bool { return info.Flags&PropFromAnnotation != 0 } +func (info *PropertyInfo) IsDeprecated() bool { return info.Deprecated } type ConstInfo struct { Pos ElementPosition Typ types.Map AccessLevel AccessLevel Value ConstValue + DeprecationInfo } +func (info *ConstInfo) IsDeprecated() bool { return info.Deprecated } + type ClassFlags uint8 const ( @@ -212,12 +217,14 @@ type ClassInfo struct { Mixins []string PackageInfo + DeprecationInfo } -func (info *ClassInfo) IsAbstract() bool { return info.Flags&ClassAbstract != 0 } -func (info *ClassInfo) IsFinal() bool { return info.Flags&ClassFinal != 0 } -func (info *ClassInfo) IsShape() bool { return info.Flags&ClassShape != 0 } -func (info *ClassInfo) IsInterface() bool { return info.Flags&ClassInterface != 0 } +func (info *ClassInfo) IsAbstract() bool { return info.Flags&ClassAbstract != 0 } +func (info *ClassInfo) IsFinal() bool { return info.Flags&ClassFinal != 0 } +func (info *ClassInfo) IsShape() bool { return info.Flags&ClassShape != 0 } +func (info *ClassInfo) IsInterface() bool { return info.Flags&ClassInterface != 0 } +func (info *ClassInfo) IsDeprecated() bool { return info.Deprecated } // TODO: rename it; it's not only class-related. type ClassParseState struct { diff --git a/src/tests/checkers/deprecated_test.go b/src/tests/checkers/deprecated_test.go index 336e78c1..7755ecb3 100644 --- a/src/tests/checkers/deprecated_test.go +++ b/src/tests/checkers/deprecated_test.go @@ -83,15 +83,149 @@ declare(strict_types = "1"); class OldClass { /** - * @deprecated property + * @deprecated prp */ -public $prp; +public $deprecated; + +public $notDeprecated; +} + +$v = new OldClass(); +echo $v->deprecated; +`) + test.Expect = []string{ + "Try to create instance of the class \\OldClass that was marked as deprecated", + "Try to call property deprecated that was marked as deprecated", + } + test.RunAndMatch() +} + +func TestDeprecatedClassPropertyConstants(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`a; + +echo SomeClass::OLD_ONE; + +echo SomeClass::OLD_TWO; +echo SomeClass::abc(); + +`) + test.Expect = []string{ + "Try to create instance of the class \\SomeClass that was marked as deprecated", + "Try to call property a that was marked as deprecated in the class \\SomeClass", + "Try to call constant OLD_ONE that was marked as deprecated", + "Try to call constant OLD_TWO that was marked as deprecated", + "Call to deprecated static method \\SomeClass::abc()", + } + test.RunAndMatch() +} + +func TestDeprecatedCallWithChainPropertyAndExplicitType(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`bar = new Bar(); +$a->bar->baz = new Baz(); + +echo $a->bar->baz->value; + +`) + test.Expect = []string{ + "Missing PHPDoc for \\Baz::getValue public", + "Try to call property value that was marked as deprecated", + } + test.RunAndMatch() +} + +// TODO: This test must fail after realisation CFG and DFG, because we can type inference correctly +func TestDeprecatedCallWithChainPropertyAndWithoutExplicitType(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`bar = new Bar(); +$a->bar->baz = new Baz(); + +echo $a->bar->baz->value; `) test.Expect = []string{ - "Has deprecated class OldClass", - "Has deprecated field in class OldClass", + "Missing PHPDoc for \\Baz::getValue public method", } test.RunAndMatch() } diff --git a/src/tests/golden/testdata/flysystem/golden.txt b/src/tests/golden/testdata/flysystem/golden.txt index 7ca6977a..1e0d3510 100644 --- a/src/tests/golden/testdata/flysystem/golden.txt +++ b/src/tests/golden/testdata/flysystem/golden.txt @@ -400,18 +400,15 @@ MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\Adapter\Polyfill\Str MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\Adapter\Polyfill\StreamedWritingTrait::update public method at testdata/flysystem/src/Adapter/Polyfill/StreamedWritingTrait.php:59 abstract public function update($pash, $contents, Config $config); ^^^^^^ -MAYBE deprecated: Has deprecated class Directory at testdata/flysystem/src/Directory.php:8 -class Directory extends Handler -^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'path' at testdata/flysystem/src/Directory.php:17 return $this->filesystem->deleteDir($this->path); ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'path' at testdata/flysystem/src/Directory.php:29 return $this->filesystem->listContents($this->path, $recursive); ^^^^^^^^^^^ -MAYBE deprecated: Has deprecated class File at testdata/flysystem/src/File.php:8 -class File extends Handler -^ +MAYBE deprecated: Try to create instance \League\Flysystem\File class that was marked as deprecated at testdata/flysystem/src/File.php:140 + return new File($this->filesystem, $newpath); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/flysystem/src/FileExistsException.php:21 public function __construct($path, $code = 0, BaseException $previous = null) ^^^^^^^^^^^^^ @@ -439,15 +436,18 @@ MAYBE typeHint: Specify the type for the parameter $config in PHPDoc, 'array' MAYBE typeHint: Specify the type for the parameter $config in PHPDoc, 'array' type hint too generic at testdata/flysystem/src/Filesystem.php:257 public function createDir($dirname, array $config = []) ^^^^^^^^^ +MAYBE deprecated: Try to create instance \League\Flysystem\File class that was marked as deprecated at testdata/flysystem/src/Filesystem.php:368 + $handler = ($metadata && $metadata['type'] === 'file') ? new File($this, $path) : new Directory($this, $path); + ^^^^^^^^^^^^^^^^^^^^^^ +MAYBE deprecated: Try to create instance \League\Flysystem\Directory class that was marked as deprecated at testdata/flysystem/src/Filesystem.php:368 + $handler = ($metadata && $metadata['type'] === 'file') ? new File($this, $path) : new Directory($this, $path); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/flysystem/src/Filesystem.php:362 public function get($path, Handler $handler = null) ^^^^^^^ WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/flysystem/src/FilesystemInterface.php:274 public function get($path, Handler $handler = null); ^^^^^^^ -MAYBE deprecated: Has deprecated class Handler at testdata/flysystem/src/Handler.php:10 -abstract class Handler -^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'path' at testdata/flysystem/src/Handler.php:61 $metadata = $this->filesystem->getMetadata($this->path); ^^^^^^^^^^^ @@ -484,7 +484,7 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/MountManager.php:275 } catch (PluginNotFoundException $e) { ^^ -MAYBE deprecatedUntagged: Call to deprecated method {\League\Flysystem\FilesystemInterface}->get() at testdata/flysystem/src/MountManager.php:646 +MAYBE deprecated: Call to deprecated method {\League\Flysystem\FilesystemInterface}->get() at testdata/flysystem/src/MountManager.php:646 return $this->getFilesystem($prefix)->get($path); ^^^ WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/flysystem/src/MountManager.php:642 diff --git a/src/tests/golden/testdata/inflector/golden.txt b/src/tests/golden/testdata/inflector/golden.txt index 0cd1a414..81f9ceab 100644 --- a/src/tests/golden/testdata/inflector/golden.txt +++ b/src/tests/golden/testdata/inflector/golden.txt @@ -1,6 +1,3 @@ -MAYBE deprecated: Has deprecated class Inflector at testdata/inflector/lib/Doctrine/Common/Inflector/Inflector.php:33 -final class Inflector -^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/inflector/lib/Doctrine/Common/Inflector/Inflector.php:54 @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in Doctrine Inflector 3.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^