From f74c4296b570fb7c49381a8d1e32ba23b98d76cf Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 11 Mar 2025 05:18:57 +0300 Subject: [PATCH 01/36] static calls, property fetching --- src/linter/block.go | 1 + src/linter/block_linter.go | 65 +++++++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index a8dc54d5..045dff05 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1220,6 +1220,7 @@ func (b *blockWalker) checkPropertyFetchNullSafety(expr *ir.PropertyFetchExpr, f "potential null dereference when accessing property '%s'", prp.Value) } } + func (b *blockWalker) handleCallArgs(args []ir.Node, fn meta.FuncInfo) { b.checkNullSafetyCallArgsF(args, fn) diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 3343caf6..97010282 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -593,14 +593,38 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { // All branches except default try to filter-out common // cases to reduce the number of type solving performed. if irutil.IsAssign(s.Expr) { + assign, _ := s.Expr.(*ir.Assign) + if v, ok := assign.Variable.(*ir.StaticPropertyFetchExpr); ok { + parseState := b.classParseState() + left, ok := parseState.Info.GetVarType(v.Class) + + if ok { + if left.Contains("null") { + b.report(s, LevelWarning, "notNullSafety", + "potential null dereference when accessing static property") + } + } + } return } - switch s.Expr.(type) { + switch expr := s.Expr.(type) { case *ir.ImportExpr, *ir.ExitExpr: // Skip. case *ir.ArrayExpr, *ir.NewExpr: // Report these even if they are not pure. report = true + case *ir.StaticCallExpr: + if v, ok := expr.Class.(*ir.SimpleVar); ok { + parseState := b.classParseState() + left, ok := parseState.Info.GetVarType(v) + + if ok { + if left.Contains("null") { + b.report(s, LevelWarning, "notNullSafety", + "potential null dereference when accessing static call throw $%s", v.Name) + } + } + } default: typ := b.walker.exprType(s.Expr) if !typ.Is("void") { @@ -1298,6 +1322,31 @@ func (b *blockLinter) checkMethodCall(e *ir.MethodCallExpr) { } } + switch caller := e.Variable.(type) { + case *ir.FunctionCallExpr: + if v, ok := caller.Function.(*ir.SimpleVar); ok { + funcCallerName, ok := solver.GetFuncName(parseState, &ir.Name{Value: v.Name}) + if ok { + parseState.Info.GetFunction(funcCallerName) + funInfo, ok := parseState.Info.GetFunction(funcCallerName) + if ok { + if funInfo.Typ.Contains("null") { + b.report(e, LevelWarning, "notNullSafety", + "potential null dereference in %s when accessing method", funInfo.Name) + } + } + } + } + case *ir.SimpleVar: + callerVarType, ok := parseState.Info.GetVarType(caller) + if ok { + if callerVarType.Contains("null") { + b.report(e, LevelWarning, "notNullSafety", + "potential null dereference in $%s when accessing method", caller.Name) + } + } + } + if call.info.Deprecated { deprecation := call.info.DeprecationInfo @@ -1388,7 +1437,9 @@ func (b *blockLinter) checkMethodCallPackage(methodClassName string, methodInfo } func (b *blockLinter) checkPropertyFetch(e *ir.PropertyFetchExpr) { - fetch := resolvePropertyFetch(b.walker.ctx.sc, b.classParseState(), b.walker.ctx.customTypes, e, b.walker.r.strictMixed) + globalMetaInfo := b.classParseState() + + fetch := resolvePropertyFetch(b.walker.ctx.sc, globalMetaInfo, b.walker.ctx.customTypes, e, b.walker.r.strictMixed) if !fetch.canAnalyze { return } @@ -1396,15 +1447,21 @@ func (b *blockLinter) checkPropertyFetch(e *ir.PropertyFetchExpr) { needShowUndefinedProperty := !fetch.callerTypeIsMixed || b.walker.r.strictMixed if !fetch.isFound && !fetch.isMagic && - !b.classParseState().IsTrait && + !globalMetaInfo.IsTrait && !b.walker.isThisInsideClosure(e.Variable) && needShowUndefinedProperty { b.report(e.Property, LevelError, "undefinedProperty", "Property {%s}->%s does not exist", fetch.propertyFetchType, fetch.propertyNode.Value) } - if fetch.isFound && !fetch.isMagic && !canAccess(b.classParseState(), fetch.className, fetch.info.AccessLevel) { + if fetch.isFound && !fetch.isMagic && !canAccess(globalMetaInfo, fetch.className, fetch.info.AccessLevel) { b.report(e.Property, LevelError, "accessLevel", "Cannot access %s property %s->%s", fetch.info.AccessLevel, fetch.className, fetch.propertyNode.Value) } + + left, ok := globalMetaInfo.Info.GetVarType(e.Variable) + if ok && left.Contains("null") { + b.report(e, LevelWarning, "notNullSafety", + "attempt to access property that can be null") + } } func (b *blockLinter) checkStaticPropertyFetch(e *ir.StaticPropertyFetchExpr) { From 6dab80f43359f8bb7ac87d554ccf72ac99f77a32 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 11 Mar 2025 05:23:13 +0300 Subject: [PATCH 02/36] refactoring --- src/linter/block_linter.go | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 97010282..66531075 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -598,11 +598,9 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { parseState := b.classParseState() left, ok := parseState.Info.GetVarType(v.Class) - if ok { - if left.Contains("null") { - b.report(s, LevelWarning, "notNullSafety", - "potential null dereference when accessing static property") - } + if ok && left.Contains("null") { + b.report(s, LevelWarning, "notNullSafety", + "potential null dereference when accessing static property") } } return @@ -618,11 +616,9 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { parseState := b.classParseState() left, ok := parseState.Info.GetVarType(v) - if ok { - if left.Contains("null") { - b.report(s, LevelWarning, "notNullSafety", - "potential null dereference when accessing static call throw $%s", v.Name) - } + if ok && left.Contains("null") { + b.report(s, LevelWarning, "notNullSafety", + "potential null dereference when accessing static call throw $%s", v.Name) } } default: @@ -1329,21 +1325,17 @@ func (b *blockLinter) checkMethodCall(e *ir.MethodCallExpr) { if ok { parseState.Info.GetFunction(funcCallerName) funInfo, ok := parseState.Info.GetFunction(funcCallerName) - if ok { - if funInfo.Typ.Contains("null") { - b.report(e, LevelWarning, "notNullSafety", - "potential null dereference in %s when accessing method", funInfo.Name) - } + if ok && funInfo.Typ.Contains("null") { + b.report(e, LevelWarning, "notNullSafety", + "potential null dereference in %s when accessing method", funInfo.Name) } } } case *ir.SimpleVar: callerVarType, ok := parseState.Info.GetVarType(caller) - if ok { - if callerVarType.Contains("null") { - b.report(e, LevelWarning, "notNullSafety", - "potential null dereference in $%s when accessing method", caller.Name) - } + if ok && callerVarType.Contains("null") { + b.report(e, LevelWarning, "notNullSafety", + "potential null dereference in $%s when accessing method", caller.Name) } } From 9496665c01b321d8e291a1f108f2e3fc121c8f3f Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 11 Mar 2025 18:23:22 +0300 Subject: [PATCH 03/36] test fix --- src/linter/block_linter.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 66531075..64f7c8e5 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -593,7 +593,10 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { // All branches except default try to filter-out common // cases to reduce the number of type solving performed. if irutil.IsAssign(s.Expr) { - assign, _ := s.Expr.(*ir.Assign) + assign, okCast := s.Expr.(*ir.Assign) + if !okCast { + return + } if v, ok := assign.Variable.(*ir.StaticPropertyFetchExpr); ok { parseState := b.classParseState() left, ok := parseState.Info.GetVarType(v.Class) @@ -621,11 +624,9 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { "potential null dereference when accessing static call throw $%s", v.Name) } } + report = b.isDiscardableExpr(s.Expr) default: - typ := b.walker.exprType(s.Expr) - if !typ.Is("void") { - report = b.walker.sideEffectFree(s.Expr) - } + report = b.isDiscardableExpr(s.Expr) } if report { @@ -633,6 +634,14 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { } } +func (b *blockLinter) isDiscardableExpr(expr ir.Node) bool { + typ := b.walker.exprType(expr) + if !typ.Is("void") { + return b.walker.sideEffectFree(expr) + } + return false +} + func (b *blockLinter) checkConstFetch(e *ir.ConstFetchExpr) { _, _, defined := solver.GetConstant(b.classParseState(), e.Constant) From 040d6fed3d2d34827b5cbe39e36b2837088c3cbe Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Wed, 12 Mar 2025 04:22:29 +0300 Subject: [PATCH 04/36] static calls as arguments nullsafety --- src/linter/block.go | 128 ++++++++++++++++++--- src/linter/block_linter.go | 14 ++- src/tests/checkers/null_safety_test.go | 147 +++++++++++++++++++++++++ 3 files changed, 273 insertions(+), 16 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index 045dff05..db1a9c0a 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1065,10 +1065,58 @@ func (b *blockWalker) checkNullSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) b.checkListExprNullSafety(arg, fn, i, a, haveVariadic) case *ir.PropertyFetchExpr: b.checkPropertyFetchNullSafety(a, fn, i, haveVariadic) + case *ir.StaticCallExpr: + b.checkStaticCallNullSafety(arg, fn, i, a, haveVariadic) + case *ir.StaticPropertyFetchExpr: + b.checkStaticPropertyFetchNullSafety(a, fn, i, haveVariadic) } } } +func (b *blockWalker) checkStaticCallNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, staticCallF *ir.StaticCallExpr, haveVariadic bool) { + funcName, ok := staticCallF.Call.(*ir.Identifier) + if !ok { + return + } + + var className string + switch classNameNode := staticCallF.Class.(type) { + case *ir.SimpleVar: + varInfo, found := b.ctx.sc.GetVar(classNameNode) + if !found { + return + } + className = varInfo.Type.String() + case *ir.Name: + className = "\\" + classNameNode.Value + } + + classInfo, ok := b.r.ctx.st.Info.GetClass(className) + if !ok { + return + } + + funcInfo, ok := classInfo.Methods.Get(funcName.Value) + if !ok { + return + } + + param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) + if haveVariadic && paramIndex >= len(fn.Params)-1 { + // For variadic parameter check, if type is mixed then skip. + if types.IsTypeMixed(param.Typ) { + return + } + } + paramAllowsNull := types.IsTypeNullable(param.Typ) + varIsNullable := types.IsTypeNullable(funcInfo.Typ) + if varIsNullable && !paramAllowsNull { + b.report(arg, LevelWarning, "notNullSafety", + "not null safety call in function %s signature of param %s when calling static function %s", + formatSlashesFuncName(fn), param.Name, funcInfo.Name) + } +} + func (b *blockWalker) checkSimpleVarNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, variable *ir.SimpleVar, haveVariadic bool) { varInfo, ok := b.ctx.sc.GetVar(variable) if !ok { @@ -1159,29 +1207,53 @@ func (b *blockWalker) checkListExprNullSafety(arg ir.Node, fn meta.FuncInfo, par } } -func (b *blockWalker) getPropertyComputedType(expr *ir.PropertyFetchExpr) (meta.ClassInfo, types.Map) { - baseCall, ok := expr.Variable.(*ir.SimpleVar) - if !ok { +func (b *blockWalker) getPropertyComputedType(expr ir.Node) (meta.ClassInfo, types.Map) { + var baseNode ir.Node + var propertyNode ir.Node + + switch e := expr.(type) { + case *ir.PropertyFetchExpr: + baseNode = e.Variable + propertyNode = e.Property + case *ir.StaticPropertyFetchExpr: + baseNode = e.Class + propertyNode = e.Property + default: return meta.ClassInfo{}, types.Map{} } - varInfo, ok := b.ctx.sc.GetVar(baseCall) - if !ok { + var classInfo meta.ClassInfo + var ok bool + var varType string + + if baseCall, ok := baseNode.(*ir.SimpleVar); ok { + varInfo, found := b.ctx.sc.GetVar(baseCall) + if !found { + return meta.ClassInfo{}, types.Map{} + } + varType = varInfo.Type.String() + } else if nameNode, ok := baseNode.(*ir.Name); ok { + varType = "\\" + nameNode.Value + } else { return meta.ClassInfo{}, types.Map{} } - classInfo, ok := b.r.ctx.st.Info.GetClass(varInfo.Type.String()) + classInfo, ok = b.r.ctx.st.Info.GetClass(varType) if !ok { return meta.ClassInfo{}, types.Map{} } - property, ok := expr.Property.(*ir.Identifier) - if !ok { + switch prop := propertyNode.(type) { + case *ir.Identifier: + propertyInfoFromClass := classInfo.Properties[prop.Value] + return classInfo, propertyInfoFromClass.Typ + case *ir.SimpleVar: + // static: $maybeClass::$value + propertyInfoFromClass := classInfo.Properties["$"+prop.Name] + return classInfo, propertyInfoFromClass.Typ + default: return meta.ClassInfo{}, types.Map{} } - - propertyInfoFromClass := classInfo.Properties[property.Value] - return classInfo, propertyInfoFromClass.Typ } func (b *blockWalker) checkPropertyFetchNullSafety(expr *ir.PropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { @@ -1200,6 +1272,17 @@ func (b *blockWalker) checkPropertyFetchNullSafety(expr *ir.PropertyFetchExpr, f return } + b.checkingPropertyFetchNullSafetyCondition(expr, propType, prp.Value, fn, paramIndex, haveVariadic) +} + +func (b *blockWalker) checkingPropertyFetchNullSafetyCondition( + expr ir.Node, + propType types.Map, + prpName string, + fn meta.FuncInfo, + paramIndex int, + haveVariadic bool, +) { isPrpNullable := types.IsTypeNullable(propType) param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) if haveVariadic && paramIndex >= len(fn.Params)-1 { @@ -1209,7 +1292,7 @@ func (b *blockWalker) checkPropertyFetchNullSafety(expr *ir.PropertyFetchExpr, f paramAllowsNull := types.IsTypeNullable(param.Typ) if isPrpNullable && !paramAllowsNull { b.report(expr, LevelWarning, "notNullSafety", - "potential null dereference when accessing property '%s'", prp.Value) + "potential null dereference when accessing property '%s'", prpName) } return } @@ -1217,10 +1300,29 @@ func (b *blockWalker) checkPropertyFetchNullSafety(expr *ir.PropertyFetchExpr, f paramAllowsNull := types.IsTypeNullable(param.Typ) if isPrpNullable && !paramAllowsNull { b.report(expr, LevelWarning, "notNullSafety", - "potential null dereference when accessing property '%s'", prp.Value) + "potential null dereference when accessing property '%s'", prpName) } } +func (b *blockWalker) checkStaticPropertyFetchNullSafety(expr *ir.StaticPropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { + // Recursively check the left part of the chain if it is also a property fetch. + if nested, ok := expr.Class.(*ir.StaticPropertyFetchExpr); ok { + b.checkStaticPropertyFetchNullSafety(nested, fn, paramIndex, haveVariadic) + } + + classInfo, propType := b.getPropertyComputedType(expr) + if classInfo.Name == "" || propType.Empty() { + return + } + + prp, ok := expr.Property.(*ir.SimpleVar) + if !ok { + return + } + + b.checkingPropertyFetchNullSafetyCondition(expr, propType, prp.Name, fn, paramIndex, haveVariadic) +} + func (b *blockWalker) handleCallArgs(args []ir.Node, fn meta.FuncInfo) { b.checkNullSafetyCallArgsF(args, fn) diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 64f7c8e5..d2c49f48 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -1466,18 +1466,26 @@ func (b *blockLinter) checkPropertyFetch(e *ir.PropertyFetchExpr) { } func (b *blockLinter) checkStaticPropertyFetch(e *ir.StaticPropertyFetchExpr) { - fetch := resolveStaticPropertyFetch(b.classParseState(), e) + globalMetaInfo := b.classParseState() + fetch := resolveStaticPropertyFetch(globalMetaInfo, e) + + left, ok := globalMetaInfo.Info.GetVarType(e.Class) + if ok && left.Contains("null") { + b.report(e, LevelWarning, "notNullSafety", + "attempt to access property that can be null") + } + if !fetch.canAnalyze { return } b.checkClassSpecialNameCase(e, fetch.className) - if !fetch.isFound && !b.classParseState().IsTrait { + if !fetch.isFound && !globalMetaInfo.IsTrait { b.report(e.Property, LevelError, "undefinedProperty", "Property %s::$%s does not exist", fetch.className, fetch.propertyName) } - if fetch.isFound && !canAccess(b.classParseState(), fetch.info.ClassName, fetch.info.Info.AccessLevel) { + if fetch.isFound && !canAccess(globalMetaInfo, fetch.info.ClassName, fetch.info.Info.AccessLevel) { b.report(e.Property, LevelError, "accessLevel", "Cannot access %s property %s::$%s", fetch.info.Info.AccessLevel, fetch.info.ClassName, fetch.propertyName) } } diff --git a/src/tests/checkers/null_safety_test.go b/src/tests/checkers/null_safety_test.go index bb8ac88a..9b5a024e 100644 --- a/src/tests/checkers/null_safety_test.go +++ b/src/tests/checkers/null_safety_test.go @@ -241,3 +241,150 @@ if ($v !== null) { test.Expect = []string{} test.RunAndMatch() } + +func TestStaticNullSafety(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`name; +`) + test.Expect = []string{ + "attempt to access property that can be null", + } + test.RunAndMatch() +} + +func TestStaticPropertyNullSafety(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(` Date: Wed, 12 Mar 2025 13:14:55 +0300 Subject: [PATCH 05/36] function calling nullability --- src/linter/block.go | 30 ++++++++++++++++++++++++++ src/tests/checkers/null_safety_test.go | 26 ++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/linter/block.go b/src/linter/block.go index db1a9c0a..afe1b3dd 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1069,10 +1069,40 @@ func (b *blockWalker) checkNullSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) b.checkStaticCallNullSafety(arg, fn, i, a, haveVariadic) case *ir.StaticPropertyFetchExpr: b.checkStaticPropertyFetchNullSafety(a, fn, i, haveVariadic) + case *ir.FunctionCallExpr: + b.checkFunctionCallNullSafety(arg, fn, i, a, haveVariadic) } } } +func (b *blockWalker) checkFunctionCallNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, funcCall *ir.FunctionCallExpr, haveVariadic bool) { + funcName, ok := funcCall.Function.(*ir.Name) + + if !ok { + return + } + + funcInfo, ok := b.linter.metaInfo().GetFunction("\\" + funcName.Value) + if !ok { + return + } + + param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) + if haveVariadic && paramIndex >= len(fn.Params)-1 { + // For variadic parameter check, if type is mixed then skip. + if types.IsTypeMixed(param.Typ) { + return + } + } + paramAllowsNull := types.IsTypeNullable(param.Typ) + varIsNullable := types.IsTypeNullable(funcInfo.Typ) + if varIsNullable && !paramAllowsNull { + b.report(arg, LevelWarning, "notNullSafety", + "not null safety call in function %s signature of param %s when calling function %s", + formatSlashesFuncName(fn), param.Name, funcInfo.Name) + } +} + func (b *blockWalker) checkStaticCallNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, staticCallF *ir.StaticCallExpr, haveVariadic bool) { funcName, ok := staticCallF.Call.(*ir.Identifier) if !ok { diff --git a/src/tests/checkers/null_safety_test.go b/src/tests/checkers/null_safety_test.go index 9b5a024e..1c4a2c40 100644 --- a/src/tests/checkers/null_safety_test.go +++ b/src/tests/checkers/null_safety_test.go @@ -388,3 +388,29 @@ test($maybeClass::hello()); } test.RunAndMatch() } + +func TestFunctionCallNullSafetyThrowVariable(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(` Date: Wed, 12 Mar 2025 15:37:01 +0300 Subject: [PATCH 06/36] fix and tests --- src/linter/block.go | 27 +++++++++++++++++---- src/tests/golden/testdata/qrcode/golden.txt | 3 +++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index afe1b3dd..8639d8c8 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1076,15 +1076,32 @@ func (b *blockWalker) checkNullSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) } func (b *blockWalker) checkFunctionCallNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, funcCall *ir.FunctionCallExpr, haveVariadic bool) { - funcName, ok := funcCall.Function.(*ir.Name) + var funcName string - if !ok { + var isClearF bool + var callType types.Map + + switch f := funcCall.Function.(type) { + case *ir.Name: + funcName = f.Value + isClearF = true + case *ir.SimpleVar: + funcName = f.Name + varInfo, found := b.ctx.sc.GetVar(f) + + if !found { + return + } + callType = varInfo.Type + default: return } - funcInfo, ok := b.linter.metaInfo().GetFunction("\\" + funcName.Value) - if !ok { + funcInfo, ok := b.linter.metaInfo().GetFunction("\\" + funcName) + if !ok && isClearF { return + } else { + callType = funcInfo.Typ } param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) @@ -1095,7 +1112,7 @@ func (b *blockWalker) checkFunctionCallNullSafety(arg ir.Node, fn meta.FuncInfo, } } paramAllowsNull := types.IsTypeNullable(param.Typ) - varIsNullable := types.IsTypeNullable(funcInfo.Typ) + varIsNullable := types.IsTypeNullable(callType) if varIsNullable && !paramAllowsNull { b.report(arg, LevelWarning, "notNullSafety", "not null safety call in function %s signature of param %s when calling function %s", diff --git a/src/tests/golden/testdata/qrcode/golden.txt b/src/tests/golden/testdata/qrcode/golden.txt index e201c4cc..3242fcd7 100644 --- a/src/tests/golden/testdata/qrcode/golden.txt +++ b/src/tests/golden/testdata/qrcode/golden.txt @@ -31,6 +31,9 @@ WARNING notNullSafety: not null safety call in function substr signature of para WARNING notNullSafety: not null safety call in function imagecolorallocate signature of param image at testdata/qrcode/qrcode.php:137 return imagecolorallocate($image, $r, $g, $b); ^^^^^^ +WARNING notNullSafety: not null safety call in function strtolower signature of param string when calling function \preg_replace at testdata/qrcode/qrcode.php:143 + switch (strtolower(preg_replace('/[^A-Za-z0-9]/', '', $options['s']))) { + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING deadCode: Unreachable code at testdata/qrcode/qrcode.php:155 return null; ^^^^ From a283fd98a7b2cdfb9496300af5a89a981ae8593c Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Wed, 12 Mar 2025 18:15:55 +0300 Subject: [PATCH 07/36] nolint --- src/linter/block.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linter/block.go b/src/linter/block.go index 8639d8c8..b333cde5 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1092,7 +1092,7 @@ func (b *blockWalker) checkFunctionCallNullSafety(arg ir.Node, fn meta.FuncInfo, if !found { return } - callType = varInfo.Type + callType = varInfo.Type // nolint:ineffassign,staticcheck default: return } From 76ee7250e6fc63e1de74f8228245e14f28f54952 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Wed, 12 Mar 2025 22:02:28 +0300 Subject: [PATCH 08/36] separated nullsafety rules --- src/linter/block.go | 32 +- src/linter/block_linter.go | 12 +- src/linter/report.go | 156 ++++++++- src/tests/golden/golden_test.go | 14 +- .../golden/testdata/embeddedrules/golden.txt | 8 +- .../golden/testdata/flysystem/golden.txt | 306 ++++++++++++++++++ src/tests/golden/testdata/idn/golden.txt | 16 +- .../golden/testdata/inflector/golden.txt | 6 + src/tests/golden/testdata/math/golden.txt | 16 +- src/tests/golden/testdata/mustache/golden.txt | 96 +++--- .../testdata/options-resolver/golden.txt | 18 ++ .../golden/testdata/parsedown/golden.txt | 234 ++++++++++++++ .../golden/testdata/phprocksyd/golden.txt | 33 ++ src/tests/golden/testdata/qrcode/golden.txt | 42 +-- .../testdata/twitter-api-php/golden.txt | 15 + .../golden/testdata/underscore/golden.txt | 87 +++++ 16 files changed, 972 insertions(+), 119 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index b333cde5..c3b9a53f 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1056,21 +1056,21 @@ func (b *blockWalker) checkNullSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) switch a := arg.(*ir.Argument).Expr.(type) { case *ir.SimpleVar: - b.checkSimpleVarNullSafety(arg, fn, i, a, haveVariadic) + b.checkSimpleVarNullSafety(arg, fn, i, a, haveVariadic) // done case *ir.ConstFetchExpr: - b.checkConstFetchNullSafety(arg, fn, i, a, haveVariadic) + b.checkConstFetchNullSafety(arg, fn, i, a, haveVariadic) // done case *ir.ArrayDimFetchExpr: - b.checkArrayDimFetchNullSafety(arg, fn, i, a, haveVariadic) + b.checkArrayDimFetchNullSafety(arg, fn, i, a, haveVariadic) // done case *ir.ListExpr: - b.checkListExprNullSafety(arg, fn, i, a, haveVariadic) + b.checkListExprNullSafety(arg, fn, i, a, haveVariadic) // done case *ir.PropertyFetchExpr: - b.checkPropertyFetchNullSafety(a, fn, i, haveVariadic) + b.checkPropertyFetchNullSafety(a, fn, i, haveVariadic) // done case *ir.StaticCallExpr: - b.checkStaticCallNullSafety(arg, fn, i, a, haveVariadic) + b.checkStaticCallNullSafety(arg, fn, i, a, haveVariadic) // done case *ir.StaticPropertyFetchExpr: - b.checkStaticPropertyFetchNullSafety(a, fn, i, haveVariadic) + b.checkStaticPropertyFetchNullSafety(a, fn, i, haveVariadic) //done case *ir.FunctionCallExpr: - b.checkFunctionCallNullSafety(arg, fn, i, a, haveVariadic) + b.checkFunctionCallNullSafety(arg, fn, i, a, haveVariadic) // done } } } @@ -1114,7 +1114,7 @@ func (b *blockWalker) checkFunctionCallNullSafety(arg ir.Node, fn meta.FuncInfo, paramAllowsNull := types.IsTypeNullable(param.Typ) varIsNullable := types.IsTypeNullable(callType) if varIsNullable && !paramAllowsNull { - b.report(arg, LevelWarning, "notNullSafety", + b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentFunctionCall", "not null safety call in function %s signature of param %s when calling function %s", formatSlashesFuncName(fn), param.Name, funcInfo.Name) } @@ -1158,7 +1158,7 @@ func (b *blockWalker) checkStaticCallNullSafety(arg ir.Node, fn meta.FuncInfo, p paramAllowsNull := types.IsTypeNullable(param.Typ) varIsNullable := types.IsTypeNullable(funcInfo.Typ) if varIsNullable && !paramAllowsNull { - b.report(arg, LevelWarning, "notNullSafety", + b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentStaticFunctionCall", "not null safety call in function %s signature of param %s when calling static function %s", formatSlashesFuncName(fn), param.Name, funcInfo.Name) } @@ -1180,7 +1180,7 @@ func (b *blockWalker) checkSimpleVarNullSafety(arg ir.Node, fn meta.FuncInfo, pa paramAllowsNull := types.IsTypeNullable(param.Typ) varIsNullable := types.IsTypeNullable(varInfo.Type) if varIsNullable && !paramAllowsNull { - b.report(arg, LevelWarning, "notNullSafety", + b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentVariable", "not null safety call in function %s signature of param %s", formatSlashesFuncName(fn), param.Name) } @@ -1198,7 +1198,7 @@ func (b *blockWalker) checkConstFetchNullSafety(arg ir.Node, fn meta.FuncInfo, p } paramAllowsNull := types.IsTypeNullable(param.Typ) if isNull && !paramAllowsNull { - b.report(arg, LevelWarning, "notNullSafety", + b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentConstFetch", "null passed to non-nullable parameter %s in function %s", param.Name, formatSlashesFuncName(fn)) } @@ -1223,7 +1223,7 @@ func (b *blockWalker) checkArrayDimFetchNullSafety(arg ir.Node, fn meta.FuncInfo } paramAllowsNull := types.IsTypeNullable(param.Typ) if types.IsTypeNullable(varInfo.Type) && !paramAllowsNull { - b.report(arg, LevelWarning, "notNullSafety", + b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentArrayDimFetch", "potential null array access in parameter %s of function %s", param.Name, formatSlashesFuncName(fn)) } @@ -1244,7 +1244,7 @@ func (b *blockWalker) checkListExprNullSafety(arg ir.Node, fn meta.FuncInfo, par if simpleVar, ok := item.Val.(*ir.SimpleVar); ok { varInfo, found := b.ctx.sc.GetVar(simpleVar) if found && types.IsTypeNullable(varInfo.Type) && !types.IsTypeNullable(param.Typ) { - b.report(arg, LevelWarning, "notNullSafety", + b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentList", "potential null value in list assignment for param %s in function %s", param.Name, formatSlashesFuncName(fn)) } @@ -1338,7 +1338,7 @@ func (b *blockWalker) checkingPropertyFetchNullSafetyCondition( } paramAllowsNull := types.IsTypeNullable(param.Typ) if isPrpNullable && !paramAllowsNull { - b.report(expr, LevelWarning, "notNullSafety", + b.report(expr, LevelWarning, "notNullSafetyFunctionArgumentPropertyFetch", "potential null dereference when accessing property '%s'", prpName) } return @@ -1346,7 +1346,7 @@ func (b *blockWalker) checkingPropertyFetchNullSafetyCondition( paramAllowsNull := types.IsTypeNullable(param.Typ) if isPrpNullable && !paramAllowsNull { - b.report(expr, LevelWarning, "notNullSafety", + b.report(expr, LevelWarning, "notNullSafetyFunctionArgumentPropertyFetch", "potential null dereference when accessing property '%s'", prpName) } } diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index d2c49f48..78e2a5a5 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -602,7 +602,7 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { left, ok := parseState.Info.GetVarType(v.Class) if ok && left.Contains("null") { - b.report(s, LevelWarning, "notNullSafety", + b.report(s, LevelWarning, "notNullSafetyPropertyFetch", "potential null dereference when accessing static property") } } @@ -620,7 +620,7 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { left, ok := parseState.Info.GetVarType(v) if ok && left.Contains("null") { - b.report(s, LevelWarning, "notNullSafety", + b.report(s, LevelWarning, "notNullSafetyStaticFunctionCall", "potential null dereference when accessing static call throw $%s", v.Name) } } @@ -1335,7 +1335,7 @@ func (b *blockLinter) checkMethodCall(e *ir.MethodCallExpr) { parseState.Info.GetFunction(funcCallerName) funInfo, ok := parseState.Info.GetFunction(funcCallerName) if ok && funInfo.Typ.Contains("null") { - b.report(e, LevelWarning, "notNullSafety", + b.report(e, LevelWarning, "notNullSafetyFunctionCall", "potential null dereference in %s when accessing method", funInfo.Name) } } @@ -1343,7 +1343,7 @@ func (b *blockLinter) checkMethodCall(e *ir.MethodCallExpr) { case *ir.SimpleVar: callerVarType, ok := parseState.Info.GetVarType(caller) if ok && callerVarType.Contains("null") { - b.report(e, LevelWarning, "notNullSafety", + b.report(e, LevelWarning, "notNullSafetyVariable", "potential null dereference in $%s when accessing method", caller.Name) } } @@ -1460,7 +1460,7 @@ func (b *blockLinter) checkPropertyFetch(e *ir.PropertyFetchExpr) { left, ok := globalMetaInfo.Info.GetVarType(e.Variable) if ok && left.Contains("null") { - b.report(e, LevelWarning, "notNullSafety", + b.report(e, LevelWarning, "notNullSafetyPropertyFetch", "attempt to access property that can be null") } } @@ -1471,7 +1471,7 @@ func (b *blockLinter) checkStaticPropertyFetch(e *ir.StaticPropertyFetchExpr) { left, ok := globalMetaInfo.Info.GetVarType(e.Class) if ok && left.Contains("null") { - b.report(e, LevelWarning, "notNullSafety", + b.report(e, LevelWarning, "notNullSafetyPropertyFetch", "attempt to access property that can be null") } diff --git a/src/linter/report.go b/src/linter/report.go index 26c247f7..76f47506 100644 --- a/src/linter/report.go +++ b/src/linter/report.go @@ -26,15 +26,169 @@ func addBuiltinCheckers(reg *CheckersRegistry) { }, { - Name: "notNullSafety", + Name: "notNullSafetyFunctionArgumentList", + Default: true, + Quickfix: false, + Comment: "Report not nullsafety call for null list", + Before: `test(list($a) = [null]);`, + After: `reported not safety call`, + }, + + { + Name: "notNullSafetyFunctionArgumentArrayDimFetch", + Default: true, + Quickfix: false, + Comment: "Report not nullsafety call", + Before: `class A { + public string $value = 'Hello'; +} + +function test(A $a): void { + echo $a->value; +} + +$arr = [new A(), null]; +test($arr[1]);`, + After: `reported not safety call`, + }, + + { + Name: "notNullSafetyFunctionArgumentConstFetch", + Default: true, + Quickfix: false, + Comment: "Report not nullsafety call", + Before: `function f(A $klass); + f(null);`, + After: `reported that null passed to non-nullable parameter.`, + }, + + { + Name: "notNullSafetyFunctionArgumentStaticFunctionCall", + Default: true, + Quickfix: false, + Comment: "Report not nullsafety call with static function call usage.", + Before: `class A { + public static function hello(): ?string { + return "Hello!"; + } +} + +function test(string $s): void { + echo $s; +} + +test(A::hello());`, + After: `reported not safety call`, + }, + + { + Name: "notNullSafetyFunctionArgumentVariable", Default: true, Quickfix: false, Comment: "Report not nullsafety call", Before: `function f(A $klass); f(null);`, + After: `reported not safety call with null in variable.`, + }, + + { + Name: "notNullSafetyFunctionArgumentFunctionCall", + Default: true, + Quickfix: false, + Comment: "Report not nullsafety function call.", + Before: `class A { + public static function hello(): ?string { + return "Hello!"; + } +} + +function test(A $s): void { + echo $s; +} + +function testNullable(): ?A{ + return new A(); +} + +test(testNullable());`, + After: `reported not safety call`, + }, + + { + Name: "notNullSafetyFunctionArgumentPropertyFetch", + Default: true, + Quickfix: false, + Comment: "Report not nullsafety fetching property in function argument.", + Before: ` +class User { + public $name = "lol"; +} + +$user = new User(); +$user = null; +echo $user->name;`, After: `reported not safety call`, }, + { + Name: "notNullSafetyPropertyFetch", + Default: true, + Quickfix: false, + Comment: "Report not nullsafety property fetch.", + Before: ` +class User { + public $name = "lol"; +} + +$user = new User(); +$user = null; +echo $user->name;`, + After: `reported not safety call`, + }, + + { + Name: "notNullSafetyVariable", + Default: true, + Quickfix: false, + Comment: "Report not nullsafety call", + Before: `$user = new User(); + +$user = null; + +echo $user->name;`, + After: `reported not safety call with null in variable.`, + }, + + { + Name: "notNullSafetyFunctionCall", + Default: true, + Quickfix: false, + Comment: "Report not nullsafety function call.", + Before: `function getUserOrNull(): ?User { echo "test"; } + +$getUserOrNull()->test();`, + After: `reported not safety function call`, + }, + + { + Name: "notNullSafetyStaticFunctionCall", + Default: true, + Quickfix: false, + Comment: "Report not nullsafety function call.", + Before: `class A { + public static function hello(): ?string { + return "Hello!"; + } +} + +function test(string $s): void { + echo $s; +} + +test(A::hello());`, + After: `reported not safety static function call`, + }, + { Name: "notExplicitNullableParam", Default: true, diff --git a/src/tests/golden/golden_test.go b/src/tests/golden/golden_test.go index 19dddd6e..88657c9e 100644 --- a/src/tests/golden/golden_test.go +++ b/src/tests/golden/golden_test.go @@ -96,7 +96,7 @@ func TestGolden(t *testing.T) { { Name: "parsedown", - Disable: []string{"missingPhpdoc", "arraySyntax", "phpAliases", "notNullSafety"}, + Disable: []string{"missingPhpdoc", "arraySyntax", "phpAliases"}, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, `stubs/phpstorm-stubs/mbstring/mbstring.php`, @@ -105,7 +105,7 @@ func TestGolden(t *testing.T) { { Name: "underscore", - Disable: []string{"missingPhpdoc", "phpAliases", "notNullSafety"}, + Disable: []string{"missingPhpdoc", "phpAliases"}, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, }, @@ -113,7 +113,7 @@ func TestGolden(t *testing.T) { { Name: "phprocksyd", - Disable: []string{"missingPhpdoc", "notNullSafety"}, + Disable: []string{"missingPhpdoc"}, Deps: []string{ `stubs/phpstorm-stubs/standard/basic.php`, `stubs/phpstorm-stubs/pcntl/pcntl.php`, @@ -124,7 +124,7 @@ func TestGolden(t *testing.T) { { Name: "flysystem", - Disable: []string{"redundantCast", "notNullSafety"}, + Disable: []string{"redundantCast"}, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, `stubs/phpstorm-stubs/SPL/SPL.php`, @@ -141,7 +141,7 @@ func TestGolden(t *testing.T) { { Name: "inflector", - Disable: []string{"missingPhpdoc", "notNullSafety"}, + Disable: []string{"missingPhpdoc"}, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, `stubs/phpstorm-stubs/SPL/SPL.php`, @@ -151,7 +151,7 @@ func TestGolden(t *testing.T) { { Name: "options-resolver", - Disable: []string{"missingPhpdoc", "notNullSafety"}, + Disable: []string{"missingPhpdoc"}, Deps: []string{ `stubs/phpstorm-stubs/SPL/SPL.php`, `stubs/phpstorm-stubs/Reflection/Reflection.php`, @@ -164,7 +164,7 @@ func TestGolden(t *testing.T) { { Name: "twitter-api-php", - Disable: []string{"missingPhpdoc", "arraySyntax", "notNullSafety"}, + Disable: []string{"missingPhpdoc", "arraySyntax"}, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, `stubs/phpstorm-stubs/SPL/SPL.php`, diff --git a/src/tests/golden/testdata/embeddedrules/golden.txt b/src/tests/golden/testdata/embeddedrules/golden.txt index 50f964aa..f3e3719c 100644 --- a/src/tests/golden/testdata/embeddedrules/golden.txt +++ b/src/tests/golden/testdata/embeddedrules/golden.txt @@ -13,19 +13,19 @@ WARNING argsOrder: Potentially incorrect haystack and needle arguments order at WARNING argsOrder: Potentially incorrect replacement and subject arguments order at testdata/embeddedrules/argsOrder.php:32 $_ = preg_replace($pat, $subj, 'replacement'); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function explode signature of param separator at testdata/embeddedrules/argsOrder.php:41 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param separator at testdata/embeddedrules/argsOrder.php:41 $_ = explode($s, '/'); ^^ WARNING argsOrder: Potentially incorrect delimiter and string arguments order at testdata/embeddedrules/argsOrder.php:41 $_ = explode($s, '/'); ^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function explode signature of param string at testdata/embeddedrules/argsOrder.php:45 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/embeddedrules/argsOrder.php:45 $_ = explode('/', $s); ^^ -WARNING notNullSafety: not null safety call in function explode signature of param separator at testdata/embeddedrules/argsOrder.php:46 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param separator at testdata/embeddedrules/argsOrder.php:46 $_ = explode($delim, $s); ^^^^^^ -WARNING notNullSafety: not null safety call in function explode signature of param string at testdata/embeddedrules/argsOrder.php:46 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/embeddedrules/argsOrder.php:46 $_ = explode($delim, $s); ^^ WARNING argsOrder: Potentially incorrect replace and string arguments order at testdata/embeddedrules/argsOrder.php:50 diff --git a/src/tests/golden/testdata/flysystem/golden.txt b/src/tests/golden/testdata/flysystem/golden.txt index bbd2f80e..5baee732 100644 --- a/src/tests/golden/testdata/flysystem/golden.txt +++ b/src/tests/golden/testdata/flysystem/golden.txt @@ -1,30 +1,177 @@ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:358 + if (preg_match('#^.*:$#', $item)) { + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function normalizeObject signature of param item at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:363 + $result[] = $this->normalizeObject($item, $base); + ^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string1 of function strnatcmp at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:379 + return strnatcmp($one['path'], $two['path']); + ^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string2 of function strnatcmp at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:379 + return strnatcmp($one['path'], $two['path']); + ^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function forFtpSystemType signature of param systemType at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:407 + throw NotSupportedException::forFtpSystemType($systemType); + ^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:434 + if (count(explode(' ', $item, 9)) !== 9) { + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:438 + list($permissions, /* $number */, /* $owner */, /* $group */, $size, $month, $day, $timeOrYear, $name) = explode(' ', $item, 9); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:502 + if (count(explode(' ', $item, 4)) !== 4) { + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:506 + list($date, $time, $size, $name) = explode(' ', $item, 4); + ^^^^^ MAYBE regexpSimplify: May re-write '/^[0-9]{2,4}-[0-9]{2}-[0-9]{2}/' as '/^\d{2,4}-\d{2}-\d{2}/' at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:536 return preg_match('/^[0-9]{2,4}-[0-9]{2}-[0-9]{2}/', $item) ? 'windows' : 'unix'; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE callSimplify: Could simplify to $permissions[0] at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:548 return substr($permissions, 0, 1) === 'd' ? 'dir' : 'file'; ^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function str_split signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:576 + return array_sum(str_split($part)); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:593 + return $line !== '' && ! preg_match('#.* \.(\.)?$|^total#', $line); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function getMetadata signature of param path at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:604 + return $this->getMetadata($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function getMetadata signature of param path at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:612 + return $this->getMetadata($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function getMetadata signature of param path at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:620 + return $this->getMetadata($path); + ^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Ftp.php:134 $this->connection = @ftp_ssl_connect($this->getHost(), $this->getPort(), $this->getTimeout()); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Ftp.php:136 $this->connection = @ftp_connect($this->getHost(), $this->getPort(), $this->getTimeout()); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:156 + $response = ftp_raw($this->connection, "OPTS UTF8 ON"); + ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:173 + ftp_set_option($this->connection, FTP_USEPASVADDRESS, ! $this->ignorePassiveAddress); + ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:176 + if ( ! ftp_pasv($this->connection, $this->passive)) { + ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:212 + $this->connection, + ^^^^^^^^^^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Ftp.php:233 @ftp_close($this->connection); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:233 + @ftp_close($this->connection); + ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function fwrite signature of param data at testdata/flysystem/src/Adapter/Ftp.php:245 + fwrite($stream, $contents); + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function guessMimeType signature of param path at testdata/flysystem/src/Adapter/Ftp.php:255 + $result['mimetype'] = $config->get('mimetype') ?: Util::guessMimeType($path, $contents); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function guessMimeType signature of param content at testdata/flysystem/src/Adapter/Ftp.php:255 + $result['mimetype'] = $config->get('mimetype') ?: Util::guessMimeType($path, $contents); + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function dirname signature of param path at testdata/flysystem/src/Adapter/Ftp.php:265 + $this->ensureDirectory(Util::dirname($path)); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_fput signature of param remote_filename at testdata/flysystem/src/Adapter/Ftp.php:267 + if ( ! ftp_fput($this->getConnection(), $path, $resource, $this->transferMode)) { + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_fput signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:267 + if ( ! ftp_fput($this->getConnection(), $path, $resource, $this->transferMode)) { + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'transferMode' at testdata/flysystem/src/Adapter/Ftp.php:267 + if ( ! ftp_fput($this->getConnection(), $path, $resource, $this->transferMode)) { + ^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_rename signature of param from at testdata/flysystem/src/Adapter/Ftp.php:301 + return ftp_rename($this->getConnection(), $path, $newpath); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_rename signature of param to at testdata/flysystem/src/Adapter/Ftp.php:301 + return ftp_rename($this->getConnection(), $path, $newpath); + ^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_delete signature of param filename at testdata/flysystem/src/Adapter/Ftp.php:309 + return ftp_delete($this->getConnection(), $path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function listDirectoryContents signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:318 + $contents = array_reverse($this->listDirectoryContents($dirname, false)); + ^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter filename of function ftp_delete at testdata/flysystem/src/Adapter/Ftp.php:322 + if ( ! ftp_delete($connection, $object['path'])) { + ^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_rmdir signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:330 + return ftp_rmdir($connection, $dirname); + ^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/flysystem/src/Adapter/Ftp.php:339 + $directories = explode('/', $dirname); + ^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Adapter/Ftp.php:370 + if (preg_match('~^\./.*~', $item)) { + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/flysystem/src/Adapter/Ftp.php:371 + $listing[$key] = substr($item, 2); + ^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Ftp.php:391 if (@ftp_chdir($this->getConnection(), $path) === true) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_chdir signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:391 + if (@ftp_chdir($this->getConnection(), $path) === true) { + ^^^^^ MAYBE regexpSimplify: May re-write '/^total [0-9]*$/' as '/^total \d*$/' at testdata/flysystem/src/Adapter/Ftp.php:407 if (preg_match('/^total [0-9]*$/', $listing[0])) { ^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter item of function normalizeObject at testdata/flysystem/src/Adapter/Ftp.php:411 + return $this->normalizeObject($listing[0], ''); + ^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function detectByFilename signature of param filename at testdata/flysystem/src/Adapter/Ftp.php:423 + $metadata['mimetype'] = MimeType::detectByFilename($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_mdtm signature of param filename at testdata/flysystem/src/Adapter/Ftp.php:433 + $timestamp = ftp_mdtm($this->getConnection(), $path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_fget signature of param remote_filename at testdata/flysystem/src/Adapter/Ftp.php:460 + $result = ftp_fget($this->getConnection(), $stream, $path, $this->transferMode); + ^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'transferMode' at testdata/flysystem/src/Adapter/Ftp.php:460 + $result = ftp_fget($this->getConnection(), $stream, $path, $this->transferMode); + ^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_chmod signature of param filename at testdata/flysystem/src/Adapter/Ftp.php:479 + if ( ! ftp_chmod($this->getConnection(), $mode, $path)) { + ^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:544 + $response = ftp_raw($this->connection, 'HELP'); + ^^^^^^^^^^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Ftp.php:570 $response = @ftp_raw($this->connection, trim($command)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:570 + $response = @ftp_raw($this->connection, trim($command)); + ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function trim signature of param string at testdata/flysystem/src/Adapter/Ftp.php:570 + $response = @ftp_raw($this->connection, trim($command)); + ^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Ftpd.php:15 if (@ftp_chdir($this->getConnection(), $path) === true) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_chdir signature of param directory at testdata/flysystem/src/Adapter/Ftpd.php:15 + if (@ftp_chdir($this->getConnection(), $path) === true) { + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_rawlist signature of param directory at testdata/flysystem/src/Adapter/Ftpd.php:37 + $listing = ftp_rawlist($this->getConnection(), $directory, $recursive); + ^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/flysystem/src/Adapter/Ftpd.php:39 + if ($listing === false || ( ! empty($listing) && substr($listing[0], 0, 5) === "ftpd:")) { + ^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function normalizeListing signature of param prefix at testdata/flysystem/src/Adapter/Ftpd.php:43 + return $this->normalizeListing($listing, $directory); + ^^^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Local.php:103 if ( ! @mkdir($root, $this->permissionMap['dir']['public'], true)) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,18 +181,96 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ MAYBE ternarySimplify: Could rewrite as `$mkdirError['message'] ?? ''` at testdata/flysystem/src/Adapter/Local.php:111 $errorMessage = isset($mkdirError['message']) ? $mkdirError['message'] : ''; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:122 + $location = $this->applyPathPrefix($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:132 + $location = $this->applyPathPrefix($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'writeFlags' at testdata/flysystem/src/Adapter/Local.php:135 + if (($size = file_put_contents($location, $contents, $this->writeFlags)) === false) { + ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'writeFlags' at testdata/flysystem/src/Adapter/Local.php:135 + if (($size = file_put_contents($location, $contents, $this->writeFlags)) === false) { + ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:155 + $location = $this->applyPathPrefix($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_copy_to_stream signature of param from at testdata/flysystem/src/Adapter/Local.php:159 + if ( ! $stream || stream_copy_to_stream($resource, $stream) === false || ! fclose($stream)) { + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:179 + $location = $this->applyPathPrefix($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:198 + $location = $this->applyPathPrefix($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'writeFlags' at testdata/flysystem/src/Adapter/Local.php:199 + $size = file_put_contents($location, $contents, $this->writeFlags); + ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function guessMimeType signature of param path at testdata/flysystem/src/Adapter/Local.php:209 + if ($mimetype = $config->get('mimetype') ?: Util::guessMimeType($path, $contents)) { + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function guessMimeType signature of param content at testdata/flysystem/src/Adapter/Local.php:209 + if ($mimetype = $config->get('mimetype') ?: Util::guessMimeType($path, $contents)) { + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function guessMimeType signature of param path at testdata/flysystem/src/Adapter/Local.php:209 + if ($mimetype = $config->get('mimetype') ?: Util::guessMimeType($path, $contents)) { + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function guessMimeType signature of param content at testdata/flysystem/src/Adapter/Local.php:209 + if ($mimetype = $config->get('mimetype') ?: Util::guessMimeType($path, $contents)) { + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:221 + $location = $this->applyPathPrefix($path); + ^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Local.php:222 $contents = @file_get_contents($location); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:236 + $location = $this->applyPathPrefix($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:237 + $destination = $this->applyPathPrefix($newpath); + ^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function dirname signature of param path at testdata/flysystem/src/Adapter/Local.php:238 + $parentDirectory = $this->applyPathPrefix(Util::dirname($newpath)); + ^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:249 + $location = $this->applyPathPrefix($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:250 + $destination = $this->applyPathPrefix($newpath); + ^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:261 + $location = $this->applyPathPrefix($path); + ^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Local.php:263 return @unlink($location); ^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:300 + $location = $this->applyPathPrefix($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:320 + $location = $this->applyPathPrefix($path); + ^^^^^ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings at testdata/flysystem/src/Adapter/Local.php:324 if (in_array($mimetype, ['application/octet-stream', 'inode/x-empty', 'application/x-empty'])) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:344 + $location = $this->applyPathPrefix($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:365 + $location = $this->applyPathPrefix($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:381 + $location = $this->applyPathPrefix($dirname); + ^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Local.php:387 if (false === @mkdir($location, $this->permissionMap['dir'][$visibility], true) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:403 + $location = $this->applyPathPrefix($dirname); + ^^^^^^^^ MAYBE invalidDocblockType: Void type can only be used as a standalone type for the return type at testdata/flysystem/src/Adapter/Local.php:444 * @return array|void ^^^^^^^^^^ @@ -55,6 +280,9 @@ WARNING invalidDocblockRef: @see tag refers to unknown symbol League\Flysystem\R WARNING invalidDocblockRef: @see tag refers to unknown symbol League\Flysystem\ReadInterface::read at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:41 * @see League\Flysystem\ReadInterface::read() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/flysystem/src/Adapter/Polyfill/StreamedWritingTrait.php:26 + return call_user_func($fallbackCall, $path, $contents, $config); + ^^^^^^^^^^^^^ MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\Adapter\Polyfill\StreamedWritingTrait::write public method at testdata/flysystem/src/Adapter/Polyfill/StreamedWritingTrait.php:58 abstract public function write($pash, $contents, Config $config); ^^^^^ @@ -103,12 +331,33 @@ WARNING notExplicitNullableParam: parameter with null default value should be ex 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); + ^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/flysystem/src/Handler.php:128 + return call_user_func_array($callback, $arguments); + ^^^^^^^^^ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/Handler.php:129 } catch (BadMethodCallException $e) { ^^ WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/flysystem/src/Handler.php:28 public function __construct(FilesystemInterface $filesystem = null, $path = null) ^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function mountFilesystem signature of param filesystem at testdata/flysystem/src/MountManager.php:57 + $this->mountFilesystem($prefix, $filesystem); + ^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function getPrefixAndPath signature of param path at testdata/flysystem/src/MountManager.php:123 + list($prefix, $path) = $this->getPrefixAndPath($path); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function invokePluginOnFilesystem signature of param prefix at testdata/flysystem/src/MountManager.php:166 + return $this->invokePluginOnFilesystem($method, $arguments, $prefix); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter visibility of function setVisibility at testdata/flysystem/src/MountManager.php:243 + return $filesystem->setVisibility($pathTo, $config['visibility']); + ^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/flysystem/src/MountManager.php:281 + return call_user_func_array($callback, $arguments); + ^^^^^^^^^ 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) { ^^ @@ -124,6 +373,15 @@ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or speci WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/Plugin/ForcedRename.php:33 } catch (FileNotFoundException $e) { ^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ucfirst signature of param string at testdata/flysystem/src/Plugin/GetWithMetadata.php:42 + if ( ! method_exists($this->filesystem, $method = 'get' . ucfirst($key))) { + ^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ucfirst signature of param string at testdata/flysystem/src/Plugin/GetWithMetadata.php:42 + if ( ! method_exists($this->filesystem, $method = 'get' . ucfirst($key))) { + ^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/flysystem/src/Plugin/PluggableTrait.php:72 + return call_user_func_array($callback, $arguments); + ^^^^^^^^^ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/Plugin/PluggableTrait.php:89 } catch (PluginNotFoundException $e) { ^^ @@ -133,21 +391,69 @@ MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\SafeStorage::storeSa MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\SafeStorage::retrieveSafely public method at testdata/flysystem/src/SafeStorage.php:28 public function retrieveSafely($key) ^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_key_exists signature of param key at testdata/flysystem/src/SafeStorage.php:30 + if (array_key_exists($key, static::$safeStorage[$this->hash])) { + ^^^^ MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\UnreadableFileException::forFileInfo public method at testdata/flysystem/src/UnreadableFileException.php:9 public static function forFileInfo(SplFileInfo $fileInfo) ^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function pathinfo signature of param path at testdata/flysystem/src/Util.php:214 + $listing[] = static::pathinfo($directory) + ['type' => 'dir']; + ^^^^^^^^^^ MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\Util::isSeekableStream public method at testdata/flysystem/src/Util.php:258 public static function isSeekableStream($resource) ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_get_meta_data signature of param stream at testdata/flysystem/src/Util.php:260 + $metadata = stream_get_meta_data($resource); + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function trim at testdata/flysystem/src/Util.php:298 + if ( ! isset($object['dirname']) || trim($object['dirname']) === '') { + ^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function trim signature of param string at testdata/flysystem/src/Util.php:304 + while (isset($parent) && trim($parent) !== '' && ! in_array($parent, $directories)) { + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function dirname signature of param path at testdata/flysystem/src/Util.php:306 + $parent = static::dirname($parent); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Util.php:341 + while (preg_match('#^[a-zA-Z]{1}:[^\\\/]#', $basename)) { + ^^^^^^^^^ MAYBE regexpSimplify: May re-write '#^[a-zA-Z]{1}:[^\\\/]#' as '#^[a-zA-Z]:[^\\/]#' at testdata/flysystem/src/Util.php:341 while (preg_match('#^[a-zA-Z]{1}:[^\\\/]#', $basename)) { ^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/flysystem/src/Util.php:342 + $basename = substr($basename, 2); + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Util.php:346 + if (preg_match('#^[a-zA-Z]{1}:$#', $basename)) { + ^^^^^^^^^ MAYBE regexpSimplify: May re-write '#^[a-zA-Z]{1}:$#' as '#^[a-zA-Z]:$#' at testdata/flysystem/src/Util.php:346 if (preg_match('#^[a-zA-Z]{1}:$#', $basename)) { ^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rtrim signature of param string at testdata/flysystem/src/Util.php:347 + $basename = rtrim($basename, ':'); + ^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $entry in PHPDoc, 'array' type hint too generic at testdata/flysystem/src/Util/ContentListingFormatter.php:52 private function addPathInfo(array $entry) ^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter path of function pathinfo at testdata/flysystem/src/Util/ContentListingFormatter.php:54 + return $entry + Util::pathinfo($entry['path']); + ^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/flysystem/src/Util/ContentListingFormatter.php:91 + ? strpos($entry['path'], $this->directory . '/') === 0 + ^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function stripos at testdata/flysystem/src/Util/ContentListingFormatter.php:92 + : stripos($entry['path'], $this->directory . '/') === 0; + ^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string2 of function strcasecmp at testdata/flysystem/src/Util/ContentListingFormatter.php:106 + : strcasecmp($this->directory, $entry['dirname']) === 0; + ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string1 of function strcasecmp at testdata/flysystem/src/Util/ContentListingFormatter.php:117 + return strcasecmp($a['path'], $b['path']); + ^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string2 of function strcasecmp at testdata/flysystem/src/Util/ContentListingFormatter.php:117 + return strcasecmp($a['path'], $b['path']); + ^^^^^^^^^^ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/Util/MimeType.php:208 } catch (ErrorException $e) { ^^ diff --git a/src/tests/golden/testdata/idn/golden.txt b/src/tests/golden/testdata/idn/golden.txt index 564ebefa..fb12b3d5 100644 --- a/src/tests/golden/testdata/idn/golden.txt +++ b/src/tests/golden/testdata/idn/golden.txt @@ -7,7 +7,7 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/idn/idn.php:67 @trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', E_USER_DEPRECATED); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function mb_strtolower signature of param string at testdata/idn/idn.php:71 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function mb_strtolower signature of param string at testdata/idn/idn.php:71 $domain = mb_strtolower($domain, 'utf-8'); ^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/idn/idn.php:87 @@ -22,13 +22,13 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/idn/idn.php:99 @trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', E_USER_DEPRECATED); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function explode signature of param string at testdata/idn/idn.php:102 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/idn/idn.php:102 $parts = explode('.', $domain); ^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/idn/idn.php:119 $idna_info = array( -WARNING notNullSafety: not null safety call in function mb_strlen signature of param string at testdata/idn/idn.php:152 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function mb_strlen signature of param string at testdata/idn/idn.php:152 $length = mb_strlen($input, 'utf-8'); ^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/idn/idn.php:195 @@ -43,10 +43,10 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/idn/idn.php:194 $codePoints = array( -WARNING notNullSafety: not null safety call in function mb_strlen signature of param string at testdata/idn/idn.php:200 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function mb_strlen signature of param string at testdata/idn/idn.php:200 $length = mb_strlen($input, 'utf-8'); ^^^^^^ -WARNING notNullSafety: not null safety call in function mb_substr signature of param string at testdata/idn/idn.php:202 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function mb_substr signature of param string at testdata/idn/idn.php:202 $char = mb_substr($input, $i, 1, 'utf-8'); ^^^^^^ MAYBE redundantCast: Expression already has int type at testdata/idn/idn.php:233 @@ -58,13 +58,13 @@ MAYBE assignOp: Could rewrite as `$k += 36` at testdata/idn/idn.php:234 MAYBE redundantCast: Expression already has int type at testdata/idn/idn.php:237 return $k + (int) (36 * $delta / ($delta + 38)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function strrpos signature of param haystack at testdata/idn/idn.php:247 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strrpos signature of param haystack at testdata/idn/idn.php:247 $pos = strrpos($input, '-'); ^^^^^^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/idn/idn.php:249 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/idn/idn.php:249 $output = substr($input, 0, $pos++); ^^^^^^ -WARNING notNullSafety: not null safety call in function strlen signature of param string at testdata/idn/idn.php:255 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/idn/idn.php:255 $inputLength = \strlen($input); ^^^^^^ MAYBE assignOp: Could rewrite as `$n += (int) ($i / $outputLength)` at testdata/idn/idn.php:274 diff --git a/src/tests/golden/testdata/inflector/golden.txt b/src/tests/golden/testdata/inflector/golden.txt index c975a6be..0cd1a414 100644 --- a/src/tests/golden/testdata/inflector/golden.txt +++ b/src/tests/golden/testdata/inflector/golden.txt @@ -25,3 +25,9 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/inflector/lib/Doctrine/Common/Inflector/Inflector.php:181 @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); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function mb_strtolower signature of param string at testdata/inflector/lib/Doctrine/Inflector/Inflector.php:242 + return mb_strtolower($tableized); + ^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function trim signature of param string at testdata/inflector/lib/Doctrine/Inflector/Inflector.php:480 + return trim($urlized, '-'); + ^^^^^^^^ diff --git a/src/tests/golden/testdata/math/golden.txt b/src/tests/golden/testdata/math/golden.txt index 80fa121a..98474b6a 100644 --- a/src/tests/golden/testdata/math/golden.txt +++ b/src/tests/golden/testdata/math/golden.txt @@ -1,28 +1,28 @@ WARNING unused: Variable $a is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/math/src/BigDecimal.php:292 [$a, $b] = $this->scaleValues($this, $that); ^^ -WARNING notNullSafety: not null safety call in function of signature of param value at testdata/math/src/BigDecimal.php:588 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function of signature of param value at testdata/math/src/BigDecimal.php:588 $that = BigNumber::of($that); ^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/math/src/BigInteger.php:435 new BigInteger($remainder) ^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function of signature of param value at testdata/math/src/BigInteger.php:742 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function of signature of param value at testdata/math/src/BigInteger.php:742 $that = BigNumber::of($that); ^^^^^ MAYBE ternarySimplify: Could rewrite as `$matches['fractional'] ?? ''` at testdata/math/src/BigNumber.php:90 $fractional = isset($matches['fractional']) ? $matches['fractional'] : ''; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function isLessThan signature of param that at testdata/math/src/BigNumber.php:173 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function isLessThan signature of param that at testdata/math/src/BigNumber.php:173 if ($min === null || $value->isLessThan($min)) { ^^^^ -WARNING notNullSafety: not null safety call in function isGreaterThan signature of param that at testdata/math/src/BigNumber.php:205 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function isGreaterThan signature of param that at testdata/math/src/BigNumber.php:205 if ($max === null || $value->isGreaterThan($max)) { ^^^^ -WARNING notNullSafety: not null safety call in function add signature of param a at testdata/math/src/BigNumber.php:241 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function add signature of param a at testdata/math/src/BigNumber.php:241 $sum = self::add($sum, $value); ^^^^ -WARNING notNullSafety: not null safety call in function minus signature of param that at testdata/math/src/BigRational.php:365 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function minus signature of param that at testdata/math/src/BigRational.php:365 return $this->minus($that)->getSign(); ^^^^^ MAYBE implicitModifiers: Specify the access modifier for \Brick\Math\Internal\Calculator::powmod method explicitly at testdata/math/src/Internal/Calculator.php:260 @@ -31,10 +31,10 @@ MAYBE implicitModifiers: Specify the access modifier for \Brick\Math\Internal\ MAYBE assignOp: Could rewrite as `$number ^= $xor` at testdata/math/src/Internal/Calculator.php:622 $number = $number ^ $xor; ^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function gmp_strval signature of param num at testdata/math/src/Internal/Calculator/GmpCalculator.php:66 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function gmp_strval signature of param num at testdata/math/src/Internal/Calculator/GmpCalculator.php:66 \gmp_strval($q), ^^ -WARNING notNullSafety: not null safety call in function gmp_strval signature of param num at testdata/math/src/Internal/Calculator/GmpCalculator.php:67 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function gmp_strval signature of param num at testdata/math/src/Internal/Calculator/GmpCalculator.php:67 \gmp_strval($r) ^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/math/src/Internal/Calculator/GmpCalculator.php:67 diff --git a/src/tests/golden/testdata/mustache/golden.txt b/src/tests/golden/testdata/mustache/golden.txt index 9987a66b..761638cd 100644 --- a/src/tests/golden/testdata/mustache/golden.txt +++ b/src/tests/golden/testdata/mustache/golden.txt @@ -1,4 +1,4 @@ -WARNING notNullSafety: not null safety call in function realpath signature of param path at testdata/mustache/src/Mustache/Autoloader.php:39 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function realpath signature of param path at testdata/mustache/src/Mustache/Autoloader.php:39 $realDir = realpath($baseDir); ^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$baseDir ?: 0` at testdata/mustache/src/Mustache/Autoloader.php:56 @@ -28,85 +28,85 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING useEval: Don't use the 'eval' function at testdata/mustache/src/Mustache/Cache/NoopCache.php:45 eval('?>' . $value); ^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter id of function section at testdata/mustache/src/Mustache/Compiler.php:98 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter id of function section at testdata/mustache/src/Mustache/Compiler.php:98 $node[Mustache_Tokenizer::NAME], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter start of function section at testdata/mustache/src/Mustache/Compiler.php:100 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter start of function section at testdata/mustache/src/Mustache/Compiler.php:100 $node[Mustache_Tokenizer::INDEX], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter end of function section at testdata/mustache/src/Mustache/Compiler.php:101 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter end of function section at testdata/mustache/src/Mustache/Compiler.php:101 $node[Mustache_Tokenizer::END], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter otag of function section at testdata/mustache/src/Mustache/Compiler.php:102 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter otag of function section at testdata/mustache/src/Mustache/Compiler.php:102 $node[Mustache_Tokenizer::OTAG], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter ctag of function section at testdata/mustache/src/Mustache/Compiler.php:103 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter ctag of function section at testdata/mustache/src/Mustache/Compiler.php:103 $node[Mustache_Tokenizer::CTAG], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$node[Mustache_Tokenizer::FILTERS] ?? array()` at testdata/mustache/src/Mustache/Compiler.php:99 isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(), ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter id of function invertedSection at testdata/mustache/src/Mustache/Compiler.php:111 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter id of function invertedSection at testdata/mustache/src/Mustache/Compiler.php:111 $node[Mustache_Tokenizer::NAME], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$node[Mustache_Tokenizer::FILTERS] ?? array()` at testdata/mustache/src/Mustache/Compiler.php:112 isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(), ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter id of function partial at testdata/mustache/src/Mustache/Compiler.php:119 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter id of function partial at testdata/mustache/src/Mustache/Compiler.php:119 $node[Mustache_Tokenizer::NAME], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$node[Mustache_Tokenizer::INDENT] ?? ''` at testdata/mustache/src/Mustache/Compiler.php:120 isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '', ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter id of function parent at testdata/mustache/src/Mustache/Compiler.php:127 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter id of function parent at testdata/mustache/src/Mustache/Compiler.php:127 $node[Mustache_Tokenizer::NAME], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$node[Mustache_Tokenizer::INDENT] ?? ''` at testdata/mustache/src/Mustache/Compiler.php:128 isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '', ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter id of function blockArg at testdata/mustache/src/Mustache/Compiler.php:137 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter id of function blockArg at testdata/mustache/src/Mustache/Compiler.php:137 $node[Mustache_Tokenizer::NAME], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter start of function blockArg at testdata/mustache/src/Mustache/Compiler.php:138 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter start of function blockArg at testdata/mustache/src/Mustache/Compiler.php:138 $node[Mustache_Tokenizer::INDEX], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter end of function blockArg at testdata/mustache/src/Mustache/Compiler.php:139 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter end of function blockArg at testdata/mustache/src/Mustache/Compiler.php:139 $node[Mustache_Tokenizer::END], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter otag of function blockArg at testdata/mustache/src/Mustache/Compiler.php:140 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter otag of function blockArg at testdata/mustache/src/Mustache/Compiler.php:140 $node[Mustache_Tokenizer::OTAG], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter ctag of function blockArg at testdata/mustache/src/Mustache/Compiler.php:141 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter ctag of function blockArg at testdata/mustache/src/Mustache/Compiler.php:141 $node[Mustache_Tokenizer::CTAG], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter id of function blockVar at testdata/mustache/src/Mustache/Compiler.php:149 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter id of function blockVar at testdata/mustache/src/Mustache/Compiler.php:149 $node[Mustache_Tokenizer::NAME], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter start of function blockVar at testdata/mustache/src/Mustache/Compiler.php:150 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter start of function blockVar at testdata/mustache/src/Mustache/Compiler.php:150 $node[Mustache_Tokenizer::INDEX], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter end of function blockVar at testdata/mustache/src/Mustache/Compiler.php:151 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter end of function blockVar at testdata/mustache/src/Mustache/Compiler.php:151 $node[Mustache_Tokenizer::END], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter otag of function blockVar at testdata/mustache/src/Mustache/Compiler.php:152 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter otag of function blockVar at testdata/mustache/src/Mustache/Compiler.php:152 $node[Mustache_Tokenizer::OTAG], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter ctag of function blockVar at testdata/mustache/src/Mustache/Compiler.php:153 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter ctag of function blockVar at testdata/mustache/src/Mustache/Compiler.php:153 $node[Mustache_Tokenizer::CTAG], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter id of function variable at testdata/mustache/src/Mustache/Compiler.php:165 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter id of function variable at testdata/mustache/src/Mustache/Compiler.php:165 $node[Mustache_Tokenizer::NAME], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$node[Mustache_Tokenizer::FILTERS] ?? array()` at testdata/mustache/src/Mustache/Compiler.php:166 isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(), ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter text of function text at testdata/mustache/src/Mustache/Compiler.php:173 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter text of function text at testdata/mustache/src/Mustache/Compiler.php:173 $code .= $this->text($node[Mustache_Tokenizer::VALUE], $level); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING unused: Variable $keystr is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/mustache/src/Mustache/Compiler.php:289 $keystr = var_export($key, true); ^^^^^^^ -WARNING notNullSafety: not null safety call in function getFindMethod signature of param id at testdata/mustache/src/Mustache/Compiler.php:556 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function getFindMethod signature of param id at testdata/mustache/src/Mustache/Compiler.php:556 $method = $this->getFindMethod($name); ^^^^^ MAYBE callSimplify: Could simplify to $id[0] at testdata/mustache/src/Mustache/Compiler.php:646 @@ -187,16 +187,16 @@ MAYBE callSimplify: Could simplify to $this->stack[] = $value at testdata/must MAYBE callSimplify: Could simplify to $this->blockStack[] = $value at testdata/mustache/src/Mustache/Context.php:49 array_push($this->blockStack, $value); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:131 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:131 $value = $this->findVariableInStack($first, $this->stack); ^^^^^^ -WARNING notNullSafety: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:138 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:138 $value = $this->findVariableInStack($chunk, array($value)); ^^^^^^ -WARNING notNullSafety: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:174 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:174 $value = $this->findVariableInStack($chunk, array($value)); ^^^^^^ -WARNING notNullSafety: not null safety call in function method_exists signature of param object_or_class at testdata/mustache/src/Mustache/Context.php:218 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function method_exists signature of param object_or_class at testdata/mustache/src/Mustache/Context.php:218 if (method_exists($frame, $id)) { ^^^^^^ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/mustache/src/Mustache/Context.php:213 @@ -205,13 +205,13 @@ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condit MAYBE ternarySimplify: Could rewrite as `$options['cache_file_mode'] ?? null` at testdata/mustache/src/Mustache/Engine.php:156 $mode = isset($options['cache_file_mode']) ? $options['cache_file_mode'] : null; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function setCache signature of param cache at testdata/mustache/src/Mustache/Engine.php:160 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function setCache signature of param cache at testdata/mustache/src/Mustache/Engine.php:160 $this->setCache($cache); ^^^^^^ -WARNING notNullSafety: potential null array access in parameter loader of function setLoader at testdata/mustache/src/Mustache/Engine.php:168 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter loader of function setLoader at testdata/mustache/src/Mustache/Engine.php:168 $this->setLoader($options['loader']); ^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter partialsLoader of function setPartialsLoader at testdata/mustache/src/Mustache/Engine.php:172 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter partialsLoader of function setPartialsLoader at testdata/mustache/src/Mustache/Engine.php:172 $this->setPartialsLoader($options['partials_loader']); ^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE misspellComment: "entitity" is a misspelling of "entity" at testdata/mustache/src/Mustache/Engine.php:254 @@ -238,10 +238,10 @@ ERROR undefinedMethod: Call to undefined method {\Mustache_Cache}->setLogger() MAYBE ternarySimplify: Could rewrite as `$this->delimiters ?: '{{ }}'` at testdata/mustache/src/Mustache/Engine.php:628 'delimiters' => $this->delimiters ? $this->delimiters : '{{ }}', ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null dereference when accessing property 'charset' at testdata/mustache/src/Mustache/Engine.php:813 +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'charset' at testdata/mustache/src/Mustache/Engine.php:813 return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags); ^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null dereference when accessing property 'strictCallables' at testdata/mustache/src/Mustache/Engine.php:813 +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'strictCallables' at testdata/mustache/src/Mustache/Engine.php:813 return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags); ^^^^^^^^^^^^^^^^^^^^^^ WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/mustache/src/Mustache/Engine.php:727 @@ -268,46 +268,46 @@ MAYBE missingPhpdoc: Missing PHPDoc for \Mustache_Exception_UnknownTemplateExc WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/mustache/src/Mustache/Exception/UnknownTemplateException.php:23 public function __construct($templateName, Exception $previous = null) ^^^^^^^^^ -WARNING notNullSafety: not null safety call in function addLoader signature of param loader at testdata/mustache/src/Mustache/Loader/CascadingLoader.php:35 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function addLoader signature of param loader at testdata/mustache/src/Mustache/Loader/CascadingLoader.php:35 $this->addLoader($loader); ^^^^^^^ -WARNING notNullSafety: potential null array access in parameter string of function ltrim at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:64 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function ltrim at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:64 $this->extension = '.' . ltrim($options['extension'], '.'); ^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: null passed to non-nullable parameter context in function file_get_contents at testdata/mustache/src/Mustache/Loader/InlineLoader.php:114 +WARNING notNullSafetyFunctionArgumentConstFetch: null passed to non-nullable parameter context in function file_get_contents at testdata/mustache/src/Mustache/Loader/InlineLoader.php:114 $data = file_get_contents($this->fileName, false, null, $this->offset); ^^^^ WARNING regexpVet: '\w' intersects with '\d' in [\w\d\.] at testdata/mustache/src/Mustache/Loader/InlineLoader.php:115 foreach (preg_split("/^@@(?= [\w\d\.]+$)/m", $data, -1) as $chunk) { ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null dereference when accessing property 'stream' at testdata/mustache/src/Mustache/Logger/StreamLogger.php:61 +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'stream' at testdata/mustache/src/Mustache/Logger/StreamLogger.php:61 fclose($this->stream); ^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function array_key_exists signature of param key at testdata/mustache/src/Mustache/Logger/StreamLogger.php:102 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_key_exists signature of param key at testdata/mustache/src/Mustache/Logger/StreamLogger.php:102 if (!array_key_exists($level, self::$levels)) { ^^^^^^ -WARNING notNullSafety: not null safety call in function writeLog signature of param level at testdata/mustache/src/Mustache/Logger/StreamLogger.php:107 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function writeLog signature of param level at testdata/mustache/src/Mustache/Logger/StreamLogger.php:107 $this->writeLog($level, $message, $context); ^^^^^^ -WARNING notNullSafety: potential null dereference when accessing property 'url' at testdata/mustache/src/Mustache/Logger/StreamLogger.php:128 +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'url' at testdata/mustache/src/Mustache/Logger/StreamLogger.php:128 $this->stream = fopen($this->url, 'a'); ^^^^^^^^^^ -WARNING notNullSafety: potential null dereference when accessing property 'stream' at testdata/mustache/src/Mustache/Logger/StreamLogger.php:136 +WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'stream' at testdata/mustache/src/Mustache/Logger/StreamLogger.php:136 fwrite($this->stream, self::formatLine($level, $message, $context)); ^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function enablePragma signature of param name at testdata/mustache/src/Mustache/Parser.php:58 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function enablePragma signature of param name at testdata/mustache/src/Mustache/Parser.php:58 $this->enablePragma($pragma); ^^^^^^^ -WARNING notNullSafety: potential null array access in parameter name of function getNameAndFilters at testdata/mustache/src/Mustache/Parser.php:88 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter name of function getNameAndFilters at testdata/mustache/src/Mustache/Parser.php:88 list($name, $filters) = $this->getNameAndFilters($token[Mustache_Tokenizer::NAME]); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter name of function enablePragma at testdata/mustache/src/Mustache/Parser.php:167 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter name of function enablePragma at testdata/mustache/src/Mustache/Parser.php:167 $this->enablePragma($token[Mustache_Tokenizer::NAME]); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter string of function substr at testdata/mustache/src/Mustache/Parser.php:235 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/mustache/src/Mustache/Parser.php:235 if (substr($next[Mustache_Tokenizer::VALUE], -1) !== "\n") { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: potential null array access in parameter subject of function preg_match at testdata/mustache/src/Mustache/Parser.php:262 +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/mustache/src/Mustache/Parser.php:262 return preg_match('/^\s*$/', $token[Mustache_Tokenizer::VALUE]); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/mustache/src/Mustache/Parser.php:307 @@ -322,15 +322,15 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING unused: Variable $v is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/mustache/src/Mustache/Template.php:122 foreach ($value as $k => $v) { ^^ -WARNING notNullSafety: not null safety call in function call_user_func signature of param callback at testdata/mustache/src/Mustache/Template.php:174 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/mustache/src/Mustache/Template.php:174 ->loadLambda((string) call_user_func($value)) ^^^^^^ -WARNING notNullSafety: not null safety call in function trim signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:110 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function trim signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:110 if ($delimiters = trim($delimiters)) { ^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:188 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:188 if (substr($lastName, -1) === '}') { ^^^^^^^^^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:189 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:189 $token[self::NAME] = trim(substr($lastName, 0, -1)); ^^^^^^^^^ diff --git a/src/tests/golden/testdata/options-resolver/golden.txt b/src/tests/golden/testdata/options-resolver/golden.txt index be7cbc6f..87db7f21 100644 --- a/src/tests/golden/testdata/options-resolver/golden.txt +++ b/src/tests/golden/testdata/options-resolver/golden.txt @@ -1,3 +1,12 @@ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function isDefined signature of param option at testdata/options-resolver/Debug/OptionsResolverIntrospector.php:31 + if (!$this->isDefined($option)) { + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function isDefined signature of param option at testdata/options-resolver/Debug/OptionsResolverIntrospector.php:31 + if (!$this->isDefined($option)) { + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_key_exists signature of param key at testdata/options-resolver/Debug/OptionsResolverIntrospector.php:35 + if (!\array_key_exists($option, $this->{$property})) { + ^^^^^^^ MAYBE typeHint: Specify the return type for the function getNormalizers in PHPDoc, 'array' type hint too generic at testdata/options-resolver/Debug/OptionsResolverIntrospector.php:94 public function getNormalizers(string $option): array ^^^^^^^^^^^^^^ @@ -34,9 +43,18 @@ WARNING invalidDocblock: @param for non-existing argument $message at testdata/o MAYBE complexity: Too big method: more than 150 lines at testdata/options-resolver/OptionsResolver.php:917 public function offsetGet($option, bool $triggerDeprecation = true) ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1000 + if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { + ^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1000 + if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { + ^^^^^^ MAYBE typeHint: Specify the type for the parameter $invalidTypes in PHPDoc, 'array' type hint too generic at testdata/options-resolver/OptionsResolver.php:1123 private function verifyTypes(string $type, $value, array &$invalidTypes, int $level = 0): bool ^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function get_class signature of param object at testdata/options-resolver/OptionsResolver.php:1221 + return \get_class($value); + ^^^^^^ MAYBE typeHint: Specify the type for the parameter $values in PHPDoc, 'array' type hint too generic at testdata/options-resolver/OptionsResolver.php:1259 private function formatValues(array $values): string ^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/parsedown/golden.txt b/src/tests/golden/testdata/parsedown/golden.txt index 5a07900a..0287d630 100644 --- a/src/tests/golden/testdata/parsedown/golden.txt +++ b/src/tests/golden/testdata/parsedown/golden.txt @@ -22,18 +22,87 @@ MAYBE typeHint: Specify the type for the parameter $lines in PHPDoc, 'array' t MAYBE typeHint: Specify the type for the parameter $lines in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:167 protected function linesElements(array $lines) ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function chop signature of param string at testdata/parsedown/parsedown.php:174 + if (chop($line) === '') + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strstr signature of param haystack at testdata/parsedown/parsedown.php:186 + while (($beforeTab = strstr($line, "\t", true)) !== false) + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:192 + . substr($line, strlen($beforeTab) + 1) + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strspn signature of param string at testdata/parsedown/parsedown.php:196 + $indent = strspn($line, ' '); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:198 + $text = $indent > 0 ? substr($line, $indent) : $line; + ^^^^^ MAYBE typeHint: Specify the type for the parameter $Component in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:319 protected function extractElement(array $Component) ^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:358 + $text = substr($Line['body'], 4); + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter times of function str_repeat at testdata/parsedown/parsedown.php:380 + $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']); + ^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:387 + $text = substr($Line['body'], 4); + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:410 + if (strpos($Line['text'], '') !== false) + ^^^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:428 protected function blockCommentContinue($Line, array $Block) ^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:437 + if (strpos($Line['text'], '-->') !== false) + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function strspn at testdata/parsedown/parsedown.php:452 + $openerLength = strspn($Line['text'], $marker); + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strspn signature of param characters at testdata/parsedown/parsedown.php:452 + $openerLength = strspn($Line['text'], $marker); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:459 + $infostring = trim(substr($Line['text'], $openerLength), "\t "); + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter times of function str_repeat at testdata/parsedown/parsedown.php:511 + $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']); + ^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function strspn at testdata/parsedown/parsedown.php:516 + if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength'] + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter characters of function strspn at testdata/parsedown/parsedown.php:516 + if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength'] + ^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function strspn at testdata/parsedown/parsedown.php:516 + if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength'] + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter characters of function strspn at testdata/parsedown/parsedown.php:516 + if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength'] + ^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:517 + and chop(substr($Line['text'], $len), ' ') === '' + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function strspn at testdata/parsedown/parsedown.php:541 + $level = strspn($Line['text'], '#'); + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function trim at testdata/parsedown/parsedown.php:548 + $text = trim($Line['text'], '#'); + ^^^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:560 'handler' => array( ^ MAYBE typeHint: Specify the type for the parameter $CurrentBlock in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:574 protected function blockList($Line, array $CurrentBlock = null) ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:578 + if (preg_match('/^('.$pattern.'([ ]++|$))(.*+)/', $Line['text'], $matches)) + ^^^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:633 'destination' => 'elements' ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,6 +112,12 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:643 protected function blockListContinue($Line, array $Block) ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:656 + and preg_match('/^[0-9]++'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:659 + and preg_match('/^'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) + ^^^^^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$matches[1] ?? ''` at testdata/parsedown/parsedown.php:674 $text = isset($matches[1]) ? $matches[1] : ''; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,9 +127,15 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:680 'handler' => array( ^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:712 + $text = substr($Line['body'], $requiredIndent); + ^^^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:729 protected function blockListComplete(array $Block) ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:750 + if (preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) + ^^^^^^^^^^^^^ MAYBE regexpSimplify: May re-write '/^>[ ]?+(.*+)/' as '/^> ?+(.*+)/' at testdata/parsedown/parsedown.php:750 if (preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) ^^^^^^^^^^^^^^^^ @@ -64,18 +145,42 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:767 protected function blockQuoteContinue($Line, array $Block) ^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:774 + if ($Line['text'][0] === '>' and preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) + ^^^^^^^^^^^^^ MAYBE regexpSimplify: May re-write '/^>[ ]?+(.*+)/' as '/^> ?+(.*+)/' at testdata/parsedown/parsedown.php:774 if ($Line['text'][0] === '>' and preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function substr_count at testdata/parsedown/parsedown.php:796 + if (substr_count($Line['text'], $marker) >= 3 and chop($Line['text'], " $marker") === '') + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr_count signature of param needle at testdata/parsedown/parsedown.php:796 + if (substr_count($Line['text'], $marker) >= 3 and chop($Line['text'], " $marker") === '') + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function chop at testdata/parsedown/parsedown.php:796 + if (substr_count($Line['text'], $marker) >= 3 and chop($Line['text'], " $marker") === '') + ^^^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:811 protected function blockSetextHeader($Line, array $Block = null) ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function chop at testdata/parsedown/parsedown.php:818 + if ($Line['indent'] < 4 and chop(chop($Line['text'], ' '), $Line['text'][0]) === '') + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:836 + if (preg_match('/^<[\/]?+(\w*)(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+(\/)?>/', $Line['text'], $matches)) + ^^^^^^^^^^^^^ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings at testdata/parsedown/parsedown.php:840 if (in_array($element, $this->textLevelElements)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:857 protected function blockMarkupContinue($Line, array $Block) ^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:874 + if (strpos($Line['text'], ']') !== false + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:875 + and preg_match('/^\[(.+?)\]:[ ]*+?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/', $Line['text'], $matches) + ^^^^^^^^^^^^^ MAYBE regexpSimplify: May re-write '/^\[(.+?)\]:[ ]*+?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/' as '/^\[(.+?)\]: *+?(?: +["'(](.+)["')])? *+$/' at testdata/parsedown/parsedown.php:875 and preg_match('/^\[(.+?)\]:[ ]*+?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/', $Line['text'], $matches) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,39 +190,135 @@ MAYBE ternarySimplify: Could rewrite as `$matches[3] ?? null` at testdata/pars MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:897 protected function blockTable($Line, array $Block = null) ^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:906 + and strpos($Line['text'], '|') === false + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:907 + and strpos($Line['text'], ':') === false + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function chop at testdata/parsedown/parsedown.php:913 + if (chop($Line['text'], ' -:|') !== '') + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function trim signature of param string at testdata/parsedown/parsedown.php:922 + $divider = trim($divider); + ^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function trim signature of param string at testdata/parsedown/parsedown.php:957 + $header = trim($header); + ^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:973 'handler' => array( ^ MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1020 protected function blockTableContinue($Line, array $Block) ^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:1027 + if (count($Block['alignments']) === 1 or $Line['text'][0] === '|' or strpos($Line['text'], '|')) + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function trim signature of param string at testdata/parsedown/parsedown.php:1033 + $row = trim($row); + ^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function trim signature of param string at testdata/parsedown/parsedown.php:1042 + $cell = trim($cell); + ^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:1046 'handler' => array( ^ MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1093 protected function paragraphContinue($Line, array $Block) ^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1242 + 'extent' => strlen($text), + ^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1262 + if (preg_match('/^(['.$marker.']++)[ ]*+(.+?)[ ]*+(?') !== false + ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1285 + and preg_match("/^<((mailto:)?$commonMarkEmail)>/i", $Excerpt['text'], $matches) + ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1316 + if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) + ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1320 + elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) + ^^^^^^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:1333 'handler' => array( ^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:1360 + $Excerpt['text']= substr($Excerpt['text'], 1); + ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1408 + if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) + ^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1414 + $remainder = substr($remainder, $extent); + ^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1421 + if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) + ^^^^^^^^^^ MAYBE regexpSimplify: May re-write '/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/' as '/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?: +("[^"]*+"|'[^']*+'))?\s*+[)]/' at testdata/parsedown/parsedown.php:1421 if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1434 + if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) + ^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strtolower signature of param string at testdata/parsedown/parsedown.php:1437 + $definition = strtolower($definition); + ^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:1465 + if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) + ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1470 + if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $Excerpt['text'], $matches)) + ^^^^^^^^^^^^^^^^ MAYBE regexpSimplify: May re-write '/^<\/\w[\w-]*+[ ]*+>/s' as '/^<\/\w[\w-]*+ *+>/s' at testdata/parsedown/parsedown.php:1470 if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1478 + if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) + ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1486 + if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches)) + ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:1497 + if (substr($Excerpt['text'], 1, 1) !== ' ' and strpos($Excerpt['text'], ';') !== false + ^^^^^^^^^^^^^^^^ MAYBE callSimplify: Could simplify to $Excerpt['text'][1] at testdata/parsedown/parsedown.php:1497 if (substr($Excerpt['text'], 1, 1) !== ' ' and strpos($Excerpt['text'], ';') !== false ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:1497 + if (substr($Excerpt['text'], 1, 1) !== ' ' and strpos($Excerpt['text'], ';') !== false + ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1498 + and preg_match('/^&(#?+[0-9a-zA-Z]++);/', $Excerpt['text'], $matches) + ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1516 + if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) + ^^^^^^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:1522 'handler' => array( ^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:1539 + if (strpos($Excerpt['context'], 'http') !== false + ^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1540 + and preg_match('/\bhttps?+:[\/]{2}[^\s<]+\b\/*+/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE) + ^^^^^^^^^^^^^^^^^^^ MAYBE regexpSimplify: May re-write '/\bhttps?+:[\/]{2}[^\s<]+\b\/*+/ui' as '~\bhttps?+:/{2}[^\s<]+\b/*+~ui' at testdata/parsedown/parsedown.php:1540 and preg_match('/\bhttps?+:[\/]{2}[^\s<]+\b\/*+/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:1562 + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w++:\/{2}[^ >]++)>/i', $Excerpt['text'], $matches)) + ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1562 + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w++:\/{2}[^ >]++)>/i', $Excerpt['text'], $matches)) + ^^^^^^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Element in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1591 protected function handle(array $Element) ^^^^^^ @@ -130,9 +331,15 @@ MAYBE typeHint: Specify the type for the parameter $Elements in PHPDoc, 'array MAYBE typeHint: Specify the type for the parameter $Element in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1637 protected function elementApplyRecursive($closure, array $Element) ^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/parsedown/parsedown.php:1639 + $Element = call_user_func($closure, $Element); + ^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Element in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1653 protected function elementApplyRecursiveDepthFirst($closure, array $Element) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/parsedown/parsedown.php:1664 + $Element = call_user_func($closure, $Element); + ^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Elements in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1669 protected function elementsApplyRecursive($closure, array $Elements) ^^^^^^^^^^^^^^^^^^^^^^ @@ -157,6 +364,18 @@ MAYBE ternarySimplify: Could rewrite as `$Element['autobreak'] ?? isset($Eleme WARNING strictCmp: 3rd argument of in_array must be true when comparing strings at testdata/parsedown/parsedown.php:1807 if ( ! in_array('', $lines) ^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param pattern at testdata/parsedown/parsedown.php:1829 + while (preg_match($regexp, $text, $matches, PREG_OFFSET_CAPTURE)) + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1829 + while (preg_match($regexp, $text, $matches, PREG_OFFSET_CAPTURE)) + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1832 + $before = substr($text, 0, $offset); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1833 + $after = substr($text, $offset + strlen($matches[0][0])); + ^^^^^ MAYBE implicitModifiers: Specify the access modifier for \Parsedown::parse method explicitly at testdata/parsedown/parsedown.php:1854 function parse($text) ^^^^^ @@ -169,6 +388,21 @@ WARNING unused: Variable $val is unused (use $_ to ignore this inspection or spe MAYBE typeHint: Specify the type for the parameter $Element in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1900 protected function filterUnsafeUrlInAttribute(array $Element, $attribute) ^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function htmlspecialchars signature of param string at testdata/parsedown/parsedown.php:1921 + return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1926 + $len = strlen($needle); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1928 + if ($len > strlen($string)) + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1934 + return strtolower(substr($string, 0, $len)) === strtolower($needle); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strtolower signature of param string at testdata/parsedown/parsedown.php:1934 + return strtolower(substr($string, 0, $len)) === strtolower($needle); + ^^^^^^^ MAYBE implicitModifiers: Specify the access modifier for \Parsedown::instance method explicitly at testdata/parsedown/parsedown.php:1938 static function instance($name = 'default') ^^^^^^^^ diff --git a/src/tests/golden/testdata/phprocksyd/golden.txt b/src/tests/golden/testdata/phprocksyd/golden.txt index 0cbf2720..9439964c 100644 --- a/src/tests/golden/testdata/phprocksyd/golden.txt +++ b/src/tests/golden/testdata/phprocksyd/golden.txt @@ -28,12 +28,36 @@ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phpro WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:129 exit(1); ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_socket_accept signature of param socket at testdata/phprocksyd/Phprocksyd.php:200 + $client = stream_socket_accept($server, self::ACCEPT_TIMEOUT, $peername); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function pcntl_wait signature of param status at testdata/phprocksyd/Phprocksyd.php:231 + $pid = pcntl_wait($status, WNOHANG); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function pcntl_wexitstatus signature of param status at testdata/phprocksyd/Phprocksyd.php:241 + $Res->retcode = pcntl_wexitstatus($status); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rtrim signature of param string at testdata/phprocksyd/Phprocksyd.php:272 + $req = rtrim($req); + ^^^^ ERROR constCase: Constant 'NULL' should be used in lower case as 'null' at testdata/phprocksyd/Phprocksyd.php:321 $n = stream_select($read, $write, $except, NULL); ^^^^ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:325 exit(1); ^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter character of function ord at testdata/phprocksyd/Phprocksyd.php:360 + return ord($buf[0]) << 24 | ord($buf[1]) << 16 | ord($buf[2]) << 8 | ord($buf[3]); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter character of function ord at testdata/phprocksyd/Phprocksyd.php:360 + return ord($buf[0]) << 24 | ord($buf[1]) << 16 | ord($buf[2]) << 8 | ord($buf[3]); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter character of function ord at testdata/phprocksyd/Phprocksyd.php:360 + return ord($buf[0]) << 24 | ord($buf[1]) << 16 | ord($buf[2]) << 8 | ord($buf[3]); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter character of function ord at testdata/phprocksyd/Phprocksyd.php:360 + return ord($buf[0]) << 24 | ord($buf[1]) << 16 | ord($buf[2]) << 8 | ord($buf[3]); + ^^^^^^^ WARNING invalidDocblock: Malformed @param $stream_id tag (maybe type is missing?) at testdata/phprocksyd/Phprocksyd.php:364 * @param $stream_id ^^^^^^^^^^ @@ -67,6 +91,9 @@ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phpro ERROR undefinedMethod: Call to undefined method {mixed}->run() at testdata/phprocksyd/Phprocksyd.php:479 $instance->run($req['params']); ^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_get_meta_data signature of param stream at testdata/phprocksyd/Phprocksyd.php:522 + $meta = stream_get_meta_data($v); + ^^ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:557 exit(1); ^^^^^^^ @@ -82,6 +109,12 @@ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phpro WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Simple.php:38 exit(1); ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_socket_accept signature of param socket at testdata/phprocksyd/Simple.php:65 + $client = stream_socket_accept($server, 1, $peername); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rtrim signature of param string at testdata/phprocksyd/Simple.php:116 + $res = json_decode(rtrim($req), true); + ^^^^ ERROR constCase: Constant 'NULL' should be used in lower case as 'null' at testdata/phprocksyd/Simple.php:158 $n = stream_select($read, $write, $except, NULL); ^^^^ diff --git a/src/tests/golden/testdata/qrcode/golden.txt b/src/tests/golden/testdata/qrcode/golden.txt index 3242fcd7..3fb44dc4 100644 --- a/src/tests/golden/testdata/qrcode/golden.txt +++ b/src/tests/golden/testdata/qrcode/golden.txt @@ -4,10 +4,10 @@ MAYBE missingPhpdoc: Missing PHPDoc for \QRCode::output_image public method at MAYBE missingPhpdoc: Missing PHPDoc for \QRCode::render_image public method at testdata/qrcode/qrcode.php:53 public function render_image() { ^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function imagecreatetruecolor signature of param width at testdata/qrcode/qrcode.php:56 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function imagecreatetruecolor signature of param width at testdata/qrcode/qrcode.php:56 $image = imagecreatetruecolor($width, $height); ^^^^^^ -WARNING notNullSafety: not null safety call in function imagecreatetruecolor signature of param height at testdata/qrcode/qrcode.php:56 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function imagecreatetruecolor signature of param height at testdata/qrcode/qrcode.php:56 $image = imagecreatetruecolor($width, $height); ^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$this->options['bc'] ?? 'FFFFFF'` at testdata/qrcode/qrcode.php:59 @@ -16,22 +16,22 @@ MAYBE ternarySimplify: Could rewrite as `$this->options['bc'] ?? 'FFFFFF'` at MAYBE ternarySimplify: Could rewrite as `$this->options['fc'] ?? '000000'` at testdata/qrcode/qrcode.php:63 $fgcolor = (isset($this->options['fc']) ? $this->options['fc'] : '000000'); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function floor signature of param num at testdata/qrcode/qrcode.php:72 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function floor signature of param num at testdata/qrcode/qrcode.php:72 $scale = (($scale > 1) ? floor($scale) : 1); ^^^^^^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:134 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:134 $r = hexdec(substr($color, 0, 2)); ^^^^^^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:135 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:135 $g = hexdec(substr($color, 2, 2)); ^^^^^^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:136 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:136 $b = hexdec(substr($color, 4, 2)); ^^^^^^ -WARNING notNullSafety: not null safety call in function imagecolorallocate signature of param image at testdata/qrcode/qrcode.php:137 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function imagecolorallocate signature of param image at testdata/qrcode/qrcode.php:137 return imagecolorallocate($image, $r, $g, $b); ^^^^^^ -WARNING notNullSafety: not null safety call in function strtolower signature of param string when calling function \preg_replace at testdata/qrcode/qrcode.php:143 +WARNING notNullSafetyFunctionArgumentFunctionCall: not null safety call in function strtolower signature of param string when calling function \preg_replace at testdata/qrcode/qrcode.php:143 switch (strtolower(preg_replace('/[^A-Za-z0-9]/', '', $options['s']))) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING deadCode: Unreachable code at testdata/qrcode/qrcode.php:155 @@ -43,7 +43,7 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing WARNING unused: Variable $mode is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/qrcode/qrcode.php:177 list($mode, $vers, $ec, $data) = $this->qr_encode_data($data, $ecl); ^^^^^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:200 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:200 $data = substr($data, 0, $max_chars); ^^^^^ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/qrcode/qrcode.php:203 @@ -52,19 +52,19 @@ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condit WARNING maybeUndefined: Possibly undefined variable $code at testdata/qrcode/qrcode.php:221 while (count($code) % 8) { ^^^^^ -WARNING notNullSafety: not null safety call in function preg_match signature of param subject at testdata/qrcode/qrcode.php:268 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/qrcode/qrcode.php:268 if (preg_match($numeric, $data)) { ^^^^^ -WARNING notNullSafety: not null safety call in function preg_match signature of param subject at testdata/qrcode/qrcode.php:271 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/qrcode/qrcode.php:271 if (preg_match($alphanumeric, $data)) { ^^^^^ -WARNING notNullSafety: not null safety call in function preg_match signature of param subject at testdata/qrcode/qrcode.php:274 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/qrcode/qrcode.php:274 if (preg_match($kanji, $data)) { ^^^^^ -WARNING notNullSafety: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:281 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:281 $length = strlen($data); ^^^^^ -WARNING notNullSafety: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:295 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:295 $length = strlen($data); ^^^^^ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testdata/qrcode/qrcode.php:297 @@ -76,7 +76,7 @@ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testd WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/qrcode/qrcode.php:296 switch ($version_group) { ^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:316 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:316 $group = substr($data, $i, 3); ^^^^^ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testdata/qrcode/qrcode.php:318 @@ -88,7 +88,7 @@ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testd WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/qrcode/qrcode.php:317 switch (strlen($group)) { ^ -WARNING notNullSafety: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:339 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:339 $length = strlen($data); ^^^^^ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testdata/qrcode/qrcode.php:341 @@ -100,7 +100,7 @@ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testd WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/qrcode/qrcode.php:340 switch ($version_group) { ^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:359 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:359 $group = substr($data, $i, 2); ^^^^^ MAYBE callSimplify: Could simplify to $group[0] at testdata/qrcode/qrcode.php:361 @@ -109,7 +109,7 @@ MAYBE callSimplify: Could simplify to $group[0] at testdata/qrcode/qrcode.php: MAYBE callSimplify: Could simplify to $group[1] at testdata/qrcode/qrcode.php:362 $c2 = strpos($alphabet, substr($group, 1, 1)); ^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:390 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:390 $length = strlen($data); ^^^^^ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testdata/qrcode/qrcode.php:393 @@ -118,13 +118,13 @@ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testd WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/qrcode/qrcode.php:391 switch ($version_group) { ^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:413 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:413 $ch = ord(substr($data, $i, 1)); ^^^^^ MAYBE callSimplify: Could simplify to $data[$i] at testdata/qrcode/qrcode.php:413 $ch = ord(substr($data, $i, 1)); ^^^^^^^^^^^^^^^^^^^^ -WARNING notNullSafety: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:428 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:428 $length = strlen($data); ^^^^^ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testdata/qrcode/qrcode.php:430 @@ -136,7 +136,7 @@ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testd WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/qrcode/qrcode.php:429 switch ($version_group) { ^ -WARNING notNullSafety: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:447 +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:447 $group = substr($data, $i, 2); ^^^^^ MAYBE callSimplify: Could simplify to $group[0] at testdata/qrcode/qrcode.php:448 diff --git a/src/tests/golden/testdata/twitter-api-php/golden.txt b/src/tests/golden/testdata/twitter-api-php/golden.txt index 2c6f30fc..37b41176 100644 --- a/src/tests/golden/testdata/twitter-api-php/golden.txt +++ b/src/tests/golden/testdata/twitter-api-php/golden.txt @@ -1,12 +1,18 @@ WARNING invalidDocblock: @package name must be a start part of class namespace at testdata/twitter-api-php/TwitterAPIExchange.php:9 * @package Twitter-API-PHP ^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/twitter-api-php/TwitterAPIExchange.php:117 + if (isset($array['status']) && substr($array['status'], 0, 1) === '@') + ^^^^^^^^^^^^^^^^ MAYBE callSimplify: Could simplify to $array['status'][0] at testdata/twitter-api-php/TwitterAPIExchange.php:117 if (isset($array['status']) && substr($array['status'], 0, 1) === '@') ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING unused: Variable $key is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/twitter-api-php/TwitterAPIExchange.php:122 foreach ($array as $key => &$value) ^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:164 + list($key, $value) = explode('=', $field); + ^^^^^^ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings at testdata/twitter-api-php/TwitterAPIExchange.php:207 if (!in_array(strtolower($requestMethod), array('post', 'get', 'put', 'delete'))) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,9 +25,18 @@ MAYBE invalidDocblockType: Use bool type instead of boolean at testdata/twitte WARNING strictCmp: 3rd argument of in_array must be true when comparing strings at testdata/twitter-api-php/TwitterAPIExchange.php:286 if (in_array(strtolower($this->requestMethod), array('put', 'delete'))) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:345 + $return[] = rawurlencode($key) . '=' . rawurlencode($value); + ^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/twitter-api-php/TwitterAPIExchange.php:366 'oauth_signature_method', 'oauth_timestamp', 'oauth_token', 'oauth_version'))) { ^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:367 + $values[] = "$key=\"" . rawurlencode($value) . "\""; + ^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function setGetfield signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:391 + $this->setGetfield($data); + ^^^^^ MAYBE invalidDocblockType: Use int type instead of integer at testdata/twitter-api-php/TwitterAPIExchange.php:404 * @return integer ^^^^^^^ diff --git a/src/tests/golden/testdata/underscore/golden.txt b/src/tests/golden/testdata/underscore/golden.txt index 0c2f2d26..9aaf1ba1 100644 --- a/src/tests/golden/testdata/underscore/golden.txt +++ b/src/tests/golden/testdata/underscore/golden.txt @@ -1,3 +1,6 @@ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/underscore/underscore.php:48 + call_user_func($iterator, $v, $k, $collection); + ^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:60 if(is_null($collection)) return self::_wrap(array()); ^^^^^^^ @@ -7,18 +10,36 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:65 $return = array(); ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/underscore/underscore.php:67 + $return[] = call_user_func($iterator, $v, $k, $collection); + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_reduce signature of param callback at testdata/underscore/underscore.php:85 + return self::_wrap(array_reduce($collection, $iterator, $memo)); + ^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:113 $return = array(); ^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:193 $return = array(); ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/underscore/underscore.php:195 + if(call_user_func($iterator, $val)) $return[] = $val; + ^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:207 $return = array(); ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/underscore/underscore.php:209 + if(!call_user_func($iterator, $val)) $return[] = $val; + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/underscore/underscore.php:224 + if(call_user_func($iterator, $val)) return $val; + ^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:248 if($n === 0) return self::_wrap(array()); ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_splice signature of param offset at testdata/underscore/underscore.php:262 + return self::_wrap(array_splice($collection, $index)); + ^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:284 if($n === 0) $result = array(); ^^^^^^^ @@ -67,6 +88,9 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:456 if($step > 0 && $step > $stop) return self::_wrap(array($start)); ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function range signature of param step at testdata/underscore/underscore.php:458 + $results = range($start, $stop, $step); + ^^^^^ MAYBE arrayAccess: Array access to non-array type \__|mixed at testdata/underscore/underscore.php:480 if(!is_array($return_arrays[$k])) $return_arrays[$k] = array(); ^^^^^^^^^^^^^^ @@ -103,6 +127,9 @@ WARNING unused: Variable $v is unused (use $_ to ignore this inspection or speci MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:545 $result = array(); ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_key_exists signature of param key at testdata/underscore/underscore.php:549 + if(!array_key_exists($key, $result)) $result[$key] = array(); + ^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:549 if(!array_key_exists($key, $result)) $result[$key] = array(); ^^^^^^^ @@ -112,6 +139,12 @@ WARNING unused: Variable $__ is unused (use $_ to ignore this inspection or spec WARNING unused: Variable $args is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/underscore/underscore.php:615 $args = self::_wrapArgs(func_get_args(), 1); ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function get_class signature of param object at testdata/underscore/underscore.php:658 + return self::_wrap(get_class_methods(get_class($object))); + ^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_key_exists signature of param key at testdata/underscore/underscore.php:703 + return self::_wrap(array_key_exists($key, $collection)); + ^^^^ ERROR undefinedProperty: Property {\__|mixed|null}->isEqual does not exist at testdata/underscore/underscore.php:723 if(is_object($a) && isset($a->isEqual)) return self::_wrap($a->isEqual($b)); ^^^^^^^ @@ -124,6 +157,18 @@ ERROR undefinedMethod: Call to undefined method {mixed|null}->isEqual() at tes MAYBE arrayAccess: Array access to non-array type \__|mixed|null at testdata/underscore/underscore.php:725 if(is_array($a) && array_key_exists('isEqual', $a)) return self::_wrap($a['isEqual']($b)); ^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function is_nan signature of param num at testdata/underscore/underscore.php:772 + return self::_wrap((is_int($item) || is_float($item)) && !is_nan($item) && !is_infinite($item)); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function is_infinite signature of param num at testdata/underscore/underscore.php:772 + return self::_wrap((is_int($item) || is_float($item)) && !is_nan($item) && !is_infinite($item)); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function get_class signature of param object at testdata/underscore/underscore.php:793 + return self::_wrap(is_object($item) && get_class($item) === 'DateTime'); + ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function is_nan signature of param num at testdata/underscore/underscore.php:800 + return self::_wrap(is_nan($item)); + ^^^^^ ERROR undefinedProperty: Property {mixed}->_uniqueId does not exist at testdata/underscore/underscore.php:822 $_instance->_uniqueId++; ^^^^^^^^^ @@ -154,30 +199,72 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing ERROR undefinedProperty: Property {mixed}->_template_settings does not exist at testdata/underscore/underscore.php:909 $ts = $class_name::getInstance()->_template_settings; ^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter pattern of function preg_match_all at testdata/underscore/underscore.php:913 + preg_match_all($ts['escape'], $code, $vars, PREG_SET_ORDER); + ^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:913 + preg_match_all($ts['escape'], $code, $vars, PREG_SET_ORDER); + ^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter pattern of function preg_match_all at testdata/underscore/underscore.php:920 + preg_match_all($ts['interpolate'], $code, $vars, PREG_SET_ORDER); + ^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:920 + preg_match_all($ts['interpolate'], $code, $vars, PREG_SET_ORDER); + ^^^^^ +WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter pattern of function preg_match_all at testdata/underscore/underscore.php:927 + preg_match_all($ts['evaluate'], $code, $vars, PREG_SET_ORDER); + ^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:927 + preg_match_all($ts['evaluate'], $code, $vars, PREG_SET_ORDER); + ^^^^^ MAYBE deprecated: Call to deprecated function create_function (since: 7.2, reason: Use anonymous functions instead, removed: 8.0) at testdata/underscore/underscore.php:940 $func = create_function('$context', $code); ^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function htmlentities signature of param string at testdata/underscore/underscore.php:952 + return self::_wrap(htmlentities($item)); + ^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:970 return md5(join('_', array( MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/underscore/underscore.php:972 var_export($args, true) ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:978 + $_instance->_memoized[$key] = call_user_func_array($function, $args); + ^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:995 $key = md5(join('', array( MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/underscore/underscore.php:997 $wait ^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1005 + return call_user_func_array($function, func_get_args()); + ^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentFunctionCall: not null safety call in function md5 signature of param string when calling function \var_export at testdata/underscore/underscore.php:1021 + $key = md5(var_export($function, true)); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1023 + $_instance->_onced[$key] = call_user_func_array($function, func_get_args()); + ^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:1036 $args = array_merge(array($function), func_get_args()); ^^^^^^^^^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1037 + return call_user_func_array($wrapper, $args); + ^^^^^^^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1068 + if($_instance->_aftered[$key] >= $count) return call_user_func_array($function, func_get_args()); + ^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:1102 $filled_args = array(); ^^^^^^^ WARNING unused: Foreach key $k is unused, can simplify $k => $v to just $v at testdata/underscore/underscore.php:1107 foreach($caller_args as $k=>$v) { ^^ +WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_pad signature of param length at testdata/underscore/underscore.php:1112 + return array_pad($filled_args, $num_args, null); + ^^^^^^^^^ ERROR classMembersOrder: Property $_uniqueId must go before methods in the class __ at testdata/underscore/underscore.php:817 public $_uniqueId = -1; ^^^^^^^^^^^^^^^^^^^^^^^ From 528f14608dbca0f738ada6bd27b88fc183ab6889 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Wed, 12 Mar 2025 22:03:58 +0300 Subject: [PATCH 09/36] doc update --- docs/checkers_doc.md | 260 ++++++++++++++++++++++++++++++++++++++++++- src/linter/block.go | 16 +-- src/linter/report.go | 2 +- 3 files changed, 266 insertions(+), 12 deletions(-) diff --git a/docs/checkers_doc.md b/docs/checkers_doc.md index 587630d2..0fe2c4bd 100644 --- a/docs/checkers_doc.md +++ b/docs/checkers_doc.md @@ -4,7 +4,7 @@ | Total checks | Checks enabled by default | Disabled checks by default | Autofixable checks | | ------------ | ------------------------- | -------------------------- | ------------------ | -| 107 | 89 | 18 | 15 | +| 117 | 99 | 18 | 15 | ## Table of contents - Enabled by default @@ -60,7 +60,17 @@ - [`newAbstract` checker](#newabstract-checker) - [`nonPublicInterfaceMember` checker](#nonpublicinterfacemember-checker) - [`notExplicitNullableParam` checker (autofixable)](#notexplicitnullableparam-checker) - - [`notNullSafety` checker](#notnullsafety-checker) + - [`notNullSafetyFunctionArgumentArrayDimFetch` checker](#notnullsafetyfunctionargumentarraydimfetch-checker) + - [`notNullSafetyFunctionArgumentConstFetch` checker](#notnullsafetyfunctionargumentconstfetch-checker) + - [`notNullSafetyFunctionArgumentFunctionCall` checker](#notnullsafetyfunctionargumentfunctioncall-checker) + - [`notNullSafetyFunctionArgumentList` checker](#notnullsafetyfunctionargumentlist-checker) + - [`notNullSafetyFunctionArgumentPropertyFetch` checker](#notnullsafetyfunctionargumentpropertyfetch-checker) + - [`notNullSafetyFunctionArgumentStaticFunctionCall` checker](#notnullsafetyfunctionargumentstaticfunctioncall-checker) + - [`notNullSafetyFunctionArgumentVariable` checker](#notnullsafetyfunctionargumentvariable-checker) + - [`notNullSafetyFunctionCall` checker](#notnullsafetyfunctioncall-checker) + - [`notNullSafetyPropertyFetch` checker](#notnullsafetypropertyfetch-checker) + - [`notNullSafetyStaticFunctionCall` checker](#notnullsafetystaticfunctioncall-checker) + - [`notNullSafetyVariable` checker](#notnullsafetyvariable-checker) - [`offBy1` checker (autofixable)](#offby1-checker) - [`oldStyleConstructor` checker](#oldstyleconstructor-checker) - [`paramClobber` checker](#paramclobber-checker) @@ -1200,7 +1210,156 @@ function f(?string $str = null);


-### `notNullSafety` checker +### `notNullSafetyFunctionArgumentArrayDimFetch` checker + +#### Description + +Report not nullsafety call array. + +#### Non-compliant code: +```php +class A { + public string $value = 'Hello'; +} + +function test(A $a): void { + echo $a->value; +} + +$arr = [new A(), null]; +test($arr[1]); +``` + +#### Compliant code: +```php +reported not safety call +``` +


+ + +### `notNullSafetyFunctionArgumentConstFetch` checker + +#### Description + +Report not nullsafety call + +#### Non-compliant code: +```php +function f(A $klass); + f(null); +``` + +#### Compliant code: +```php +reported that null passed to non-nullable parameter. +``` +


+ + +### `notNullSafetyFunctionArgumentFunctionCall` checker + +#### Description + +Report not nullsafety function call. + +#### Non-compliant code: +```php +class A { + public static function hello(): ?string { + return "Hello!"; + } +} + +function test(A $s): void { + echo $s; +} + +function testNullable(): ?A{ + return new A(); +} + +test(testNullable()); +``` + +#### Compliant code: +```php +reported not safety call +``` +


+ + +### `notNullSafetyFunctionArgumentList` checker + +#### Description + +Report not nullsafety call for null list + +#### Non-compliant code: +```php +test(list($a) = [null]); +``` + +#### Compliant code: +```php +reported not safety call +``` +


+ + +### `notNullSafetyFunctionArgumentPropertyFetch` checker + +#### Description + +Report not nullsafety fetching property in function argument. + +#### Non-compliant code: +```php + +class User { + public $name = "lol"; +} + +$user = new User(); +$user = null; +echo $user->name; +``` + +#### Compliant code: +```php +reported not safety call +``` +


+ + +### `notNullSafetyFunctionArgumentStaticFunctionCall` checker + +#### Description + +Report not nullsafety call with static function call usage. + +#### Non-compliant code: +```php +class A { + public static function hello(): ?string { + return "Hello!"; + } +} + +function test(string $s): void { + echo $s; +} + +test(A::hello()); +``` + +#### Compliant code: +```php +reported not safety call +``` +


+ + +### `notNullSafetyFunctionArgumentVariable` checker #### Description @@ -1212,6 +1371,51 @@ function f(A $klass); f(null); ``` +#### Compliant code: +```php +reported not safety call with null in variable. +``` +


+ + +### `notNullSafetyFunctionCall` checker + +#### Description + +Report not nullsafety function call. + +#### Non-compliant code: +```php +function getUserOrNull(): ?User { echo "test"; } + +$getUserOrNull()->test(); +``` + +#### Compliant code: +```php +reported not safety function call +``` +


+ + +### `notNullSafetyPropertyFetch` checker + +#### Description + +Report not nullsafety property fetch. + +#### Non-compliant code: +```php + +class User { + public $name = "lol"; +} + +$user = new User(); +$user = null; +echo $user->name; +``` + #### Compliant code: ```php reported not safety call @@ -1219,6 +1423,56 @@ reported not safety call


+### `notNullSafetyStaticFunctionCall` checker + +#### Description + +Report not nullsafety function call. + +#### Non-compliant code: +```php +class A { + public static function hello(): ?string { + return "Hello!"; + } +} + +function test(string $s): void { + echo $s; +} + +test(A::hello()); +``` + +#### Compliant code: +```php +reported not safety static function call +``` +


+ + +### `notNullSafetyVariable` checker + +#### Description + +Report not nullsafety call + +#### Non-compliant code: +```php +$user = new User(); + +$user = null; + +echo $user->name; +``` + +#### Compliant code: +```php +reported not safety call with null in variable. +``` +


+ + ### `offBy1` checker > Auto fix available diff --git a/src/linter/block.go b/src/linter/block.go index c3b9a53f..1a623928 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1056,21 +1056,21 @@ func (b *blockWalker) checkNullSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) switch a := arg.(*ir.Argument).Expr.(type) { case *ir.SimpleVar: - b.checkSimpleVarNullSafety(arg, fn, i, a, haveVariadic) // done + b.checkSimpleVarNullSafety(arg, fn, i, a, haveVariadic) case *ir.ConstFetchExpr: - b.checkConstFetchNullSafety(arg, fn, i, a, haveVariadic) // done + b.checkConstFetchNullSafety(arg, fn, i, a, haveVariadic) case *ir.ArrayDimFetchExpr: - b.checkArrayDimFetchNullSafety(arg, fn, i, a, haveVariadic) // done + b.checkArrayDimFetchNullSafety(arg, fn, i, a, haveVariadic) case *ir.ListExpr: - b.checkListExprNullSafety(arg, fn, i, a, haveVariadic) // done + b.checkListExprNullSafety(arg, fn, i, a, haveVariadic) case *ir.PropertyFetchExpr: - b.checkPropertyFetchNullSafety(a, fn, i, haveVariadic) // done + b.checkPropertyFetchNullSafety(a, fn, i, haveVariadic) case *ir.StaticCallExpr: - b.checkStaticCallNullSafety(arg, fn, i, a, haveVariadic) // done + b.checkStaticCallNullSafety(arg, fn, i, a, haveVariadic) case *ir.StaticPropertyFetchExpr: - b.checkStaticPropertyFetchNullSafety(a, fn, i, haveVariadic) //done + b.checkStaticPropertyFetchNullSafety(a, fn, i, haveVariadic) case *ir.FunctionCallExpr: - b.checkFunctionCallNullSafety(arg, fn, i, a, haveVariadic) // done + b.checkFunctionCallNullSafety(arg, fn, i, a, haveVariadic) } } } diff --git a/src/linter/report.go b/src/linter/report.go index 76f47506..b8b9b664 100644 --- a/src/linter/report.go +++ b/src/linter/report.go @@ -38,7 +38,7 @@ func addBuiltinCheckers(reg *CheckersRegistry) { Name: "notNullSafetyFunctionArgumentArrayDimFetch", Default: true, Quickfix: false, - Comment: "Report not nullsafety call", + Comment: "Report not nullsafety call array.", Before: `class A { public string $value = 'Hello'; } From a1abd5faa4ed0ccd48f829fcf193499b3ddb10eb Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 18 Mar 2025 18:41:18 +0300 Subject: [PATCH 10/36] kphp toggle --- src/linter/block.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/linter/block.go b/src/linter/block.go index 1a623928..1a9b06a4 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1039,6 +1039,10 @@ func formatSlashesFuncName(fn meta.FuncInfo) string { } func (b *blockWalker) checkNullSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) { + if b.r.config.KPHP && strings.Contains(fn.Name, "\\tuple") || strings.Contains(fn.Name, "\\shape") { + return + } + if fn.Params == nil || fn.Name == "" { return } From 2bc89de3319010972d4b9b857e70fb7637c63dc1 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Wed, 19 Mar 2025 14:16:37 +0300 Subject: [PATCH 11/36] better way to handle typing --- src/linter/block.go | 4 ---- src/types/predicates.go | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index 1a9b06a4..1a623928 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1039,10 +1039,6 @@ func formatSlashesFuncName(fn meta.FuncInfo) string { } func (b *blockWalker) checkNullSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) { - if b.r.config.KPHP && strings.Contains(fn.Name, "\\tuple") || strings.Contains(fn.Name, "\\shape") { - return - } - if fn.Params == nil || fn.Name == "" { return } diff --git a/src/types/predicates.go b/src/types/predicates.go index 3d963e3f..3c7b2848 100644 --- a/src/types/predicates.go +++ b/src/types/predicates.go @@ -39,7 +39,7 @@ func IsAlias(s string) bool { func IsTypeNullable(typ Map) bool { isNullable := false - if typ.m == nil { + if typ.m == nil || typ.Empty() { return true // We consider that if the type is not inferred, then it is mixed } typ.Iterate(func(t string) { From 77c45776303ce118fc033183b61401abc253cf02 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Sun, 23 Mar 2025 21:07:02 +0300 Subject: [PATCH 12/36] improved type inferring for null and false in conditions identical --- src/linter/and_walker.go | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/linter/and_walker.go b/src/linter/and_walker.go index 962c2d76..393f22d6 100644 --- a/src/linter/and_walker.go +++ b/src/linter/and_walker.go @@ -191,6 +191,14 @@ func (a *andWalker) EnterNode(w ir.Node) (res bool) { // TODO: actually this needs to be present inside if body only } + case *ir.NotIdenticalExpr: + a.handleConditionSafety(n.Left, n.Right, false) + a.handleConditionSafety(n.Right, n.Left, false) + + case *ir.IdenticalExpr: + a.handleConditionSafety(n.Left, n.Right, true) + a.handleConditionSafety(n.Right, n.Left, true) + case *ir.BooleanNotExpr: a.inNot = true @@ -219,6 +227,47 @@ func (a *andWalker) EnterNode(w ir.Node) (res bool) { return res } +func (a *andWalker) handleConditionSafety(left ir.Node, right ir.Node, identical bool) { + variable, ok := left.(*ir.SimpleVar) + if !ok { + return + } + + constValue, ok := right.(*ir.ConstFetchExpr) + if !ok || (constValue.Constant.Value != "false" && constValue.Constant.Value != "null") { + return + } + + // We need to traverse the variable here to check that + // it exists, since this variable will be added to the + // context later. + a.b.handleVariable(variable) + + currentVar, isGotVar := a.trueContext.sc.GetVar(variable) + if !isGotVar { + return + } + + var currentType types.Map + if a.inNot { + currentType = a.exprTypeInContext(a.trueContext, variable) + } else { + currentType = a.exprTypeInContext(a.falseContext, variable) + } + + if constValue.Constant.Value == "false" || constValue.Constant.Value == "null" { + clearType := currentType.Erase(constValue.Constant.Value) + if identical { + a.trueContext.sc.ReplaceVar(variable, currentType.Erase(clearType.String()), "type narrowing", currentVar.Flags) + a.falseContext.sc.ReplaceVar(variable, clearType, "type narrowing", currentVar.Flags) + } else { + a.trueContext.sc.ReplaceVar(variable, clearType, "type narrowing", currentVar.Flags) + a.falseContext.sc.ReplaceVar(variable, currentType.Erase(clearType.String()), "type narrowing", currentVar.Flags) + } + return + } +} + func (a *andWalker) runRules(w ir.Node) { kind := ir.GetNodeKind(w) if a.b.r.anyRset != nil { From f0cedb6f4b2148200dbc527f1ddb8d1e2a89995d Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Sun, 23 Mar 2025 21:08:33 +0300 Subject: [PATCH 13/36] new rules and refactoring --- src/linter/block_linter.go | 63 ++++++++++++++++++++++++++++++-------- src/linter/report.go | 33 ++++++++++++++++++++ 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 78e2a5a5..b5009548 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -606,6 +606,26 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { "potential null dereference when accessing static property") } } + + /* if _, ok := assign.Expr.(*ir.FunctionCallExpr); ok { + //currentVar, isGotVar := b.metaInfo().GetVar(assign.Variable) + + if currentVariable, isFound := b.walker.ctx.sc.GetVar(assign.Variable); isFound { + newTyp := solver.ExprType(b.walker.ctx.sc, b.walker.r.ctx.st, assign.Expr) + b.walker.ctx.sc.ReplaceVar(assign.Variable, newTyp, "recalculated via function return type", currentVariable.Flags) + } else { + currentVar, isGotVar := b.metaInfo().GetVar(assign.Variable) + if isGotVar { + newTyp := solver.ExprType(b.walker.ctx.sc, b.walker.r.ctx.st, assign.Expr) + b.walker.ctx.sc.AddVar(assign.Variable, newTyp, "recalculated via function return type", currentVar.Flags) + } + } + }*/ + + /* if callExpr, ok := assign.Expr.(*ir.MethodCallExpr); ok { + testVar, _ := b.walker.ctx.sc.GetVar(callExpr.Variable) + println(testVar) + }*/ return } switch expr := s.Expr.(type) { @@ -1329,22 +1349,28 @@ func (b *blockLinter) checkMethodCall(e *ir.MethodCallExpr) { switch caller := e.Variable.(type) { case *ir.FunctionCallExpr: - if v, ok := caller.Function.(*ir.SimpleVar); ok { - funcCallerName, ok := solver.GetFuncName(parseState, &ir.Name{Value: v.Name}) - if ok { - parseState.Info.GetFunction(funcCallerName) - funInfo, ok := parseState.Info.GetFunction(funcCallerName) - if ok && funInfo.Typ.Contains("null") { - b.report(e, LevelWarning, "notNullSafetyFunctionCall", - "potential null dereference in %s when accessing method", funInfo.Name) - } + var funcName string + var ok bool + + switch fn := caller.Function.(type) { + case *ir.SimpleVar: + funcName, ok = solver.GetFuncName(parseState, &ir.Name{Value: fn.Name}) + + case *ir.Name: + funcName, ok = solver.GetFuncName(parseState, fn) + } + if ok { + funInfo, found := parseState.Info.GetFunction(funcName) + if found { + funcType := funInfo.Typ + b.checkSafetyMethodCall(e, funcType, funInfo.Name, "FunctionCall") } } + case *ir.SimpleVar: - callerVarType, ok := parseState.Info.GetVarType(caller) - if ok && callerVarType.Contains("null") { - b.report(e, LevelWarning, "notNullSafetyVariable", - "potential null dereference in $%s when accessing method", caller.Name) + varType, ok := b.walker.ctx.sc.GetVarType(caller) + if ok { + b.checkSafetyMethodCall(e, varType, caller.Name, "Variable") } } @@ -1365,6 +1391,17 @@ func (b *blockLinter) checkMethodCall(e *ir.MethodCallExpr) { } } +func (b *blockLinter) checkSafetyMethodCall(e *ir.MethodCallExpr, typ types.Map, name string, suffix string) { + if typ.Contains("null") { + b.report(e, LevelWarning, "notNullSafety"+suffix, + "potential null dereference in %s when accessing method", name) + } + if typ.Contains("false") { + b.report(e, LevelWarning, "notFalseSafety"+suffix, + "potential false in %s when accessing method", name) + } +} + func (b *blockLinter) checkStaticCall(e *ir.StaticCallExpr) { if utils.NameNodeToString(e.Class) == "parent" && b.classParseState().CurrentParentClass == "" { b.report(e, LevelError, "parentNotFound", "Cannot call method on parent as this class does not extend another") diff --git a/src/linter/report.go b/src/linter/report.go index b8b9b664..c8c71f0d 100644 --- a/src/linter/report.go +++ b/src/linter/report.go @@ -25,6 +25,39 @@ func addBuiltinCheckers(reg *CheckersRegistry) { After: `$s = strip_tags($s, '
')`, }, + { + Name: "notFalseSafetyFunctionCall", + Default: true, + Quickfix: false, + Comment: "Report not false-safety call", + Before: `/** + * @return User|false + */ +function getUser():User|false { + return null; +} +$a = getUser()->do(); +`, + After: `reported not false-safety call`, + }, + + { + Name: "notFalseSafetyVariable", + Default: true, + Quickfix: false, + Comment: "Report not false-safety call", + Before: `/** + * @return User|false + */ +function getUser():User|false { + return null; +} +$a = getUser(); +$b = $a->do(); +`, + After: `reported not false-safety call`, + }, + { Name: "notNullSafetyFunctionArgumentList", Default: true, From aac362ae44031308ca1e269f3dd45e4cd2f86d79 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Sun, 23 Mar 2025 21:08:44 +0300 Subject: [PATCH 14/36] comments removing --- src/linter/block_linter.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index b5009548..96ac4a49 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -606,26 +606,6 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { "potential null dereference when accessing static property") } } - - /* if _, ok := assign.Expr.(*ir.FunctionCallExpr); ok { - //currentVar, isGotVar := b.metaInfo().GetVar(assign.Variable) - - if currentVariable, isFound := b.walker.ctx.sc.GetVar(assign.Variable); isFound { - newTyp := solver.ExprType(b.walker.ctx.sc, b.walker.r.ctx.st, assign.Expr) - b.walker.ctx.sc.ReplaceVar(assign.Variable, newTyp, "recalculated via function return type", currentVariable.Flags) - } else { - currentVar, isGotVar := b.metaInfo().GetVar(assign.Variable) - if isGotVar { - newTyp := solver.ExprType(b.walker.ctx.sc, b.walker.r.ctx.st, assign.Expr) - b.walker.ctx.sc.AddVar(assign.Variable, newTyp, "recalculated via function return type", currentVar.Flags) - } - } - }*/ - - /* if callExpr, ok := assign.Expr.(*ir.MethodCallExpr); ok { - testVar, _ := b.walker.ctx.sc.GetVar(callExpr.Variable) - println(testVar) - }*/ return } switch expr := s.Expr.(type) { From 4e5a3c55b1bad66076b7b09224c2ae14826f615f Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Sun, 23 Mar 2025 21:08:58 +0300 Subject: [PATCH 15/36] test fixes --- src/tests/checkers/null_safety_test.go | 7 +++++-- src/tests/checkers/strict_mixed_test.go | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/tests/checkers/null_safety_test.go b/src/tests/checkers/null_safety_test.go index 1c4a2c40..c18e537a 100644 --- a/src/tests/checkers/null_safety_test.go +++ b/src/tests/checkers/null_safety_test.go @@ -156,7 +156,6 @@ testVariadic(new A(), null); test.RunAndMatch() } -// TODO: After realisation Control Flow Graph (CFG) и Data Flow Graph (DFG) this test must fail func TestIfNullCheckSafe(t *testing.T) { test := linttest.NewSuite(t) test.AddFile(`f()", "Call to undefined method {mixed|null}->f()", "Call to undefined method {\\stdClass|null}->f()", + "potential null dereference in a when accessing method", + "potential null dereference in a when accessing method", + "potential null dereference in a when accessing method", + "potential null dereference in a when accessing method", } test.RunAndMatch() } @@ -131,6 +135,10 @@ function f(stdClass|null $a) { test.Expect = []string{ "Cannot find referenced variable $a", "Call to undefined method {\\Foo}->f()", + "potential null dereference in a when accessing method", + "potential null dereference in a when accessing method", + "potential null dereference in a when accessing method", + "potential null dereference in a when accessing method", } test.RunAndMatch() } From a772edcfd6de1eaa28710032f35e6aace24da564 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Sun, 23 Mar 2025 21:09:29 +0300 Subject: [PATCH 16/36] draft for false-safety tests --- src/tests/checkers/false_safety_test.go | 223 ++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 src/tests/checkers/false_safety_test.go diff --git a/src/tests/checkers/false_safety_test.go b/src/tests/checkers/false_safety_test.go new file mode 100644 index 00000000..7216981e --- /dev/null +++ b/src/tests/checkers/false_safety_test.go @@ -0,0 +1,223 @@ +package checkers + +import ( + "github.com/VKCOM/noverify/src/linttest" + "testing" +) + +func TestFunctionPassingFalse_SimpleVar(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`prop); +`) + test.Expect = []string{ + "false passed to non-falseable parameter s in function test", + } + test.RunAndMatch() +} + +func TestFunctionPassingFalse_StaticCall(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`do(); +} +`) + test.Expect = []string{ + "Missing PHPDoc for \\User::do public method", + } + test.RunAndMatch() +} + +func TestNotEqualFalseElseCondition(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`do(); +} else{ +$a = $b->do(); +} +`) + test.Expect = []string{ + "Missing PHPDoc for \\User::do public method", + "Call to undefined method", + "potential false in b when accessing method", + "Duplicated if/else actions", + } + test.RunAndMatch() +} + +func TestAssignFalseMethodCall(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`do(); + +`) + test.Expect = []string{ + "Missing PHPDoc for \\User::do public method", + "potential false in \\getUser when accessing method", + } + test.RunAndMatch() +} From 9e3f1565caaa8abf9842dde559596ea8fb29f3c4 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Fri, 28 Mar 2025 20:14:21 +0300 Subject: [PATCH 17/36] implemented safety call for func args (types checking), new tests --- src/linter/block.go | 212 ++++++++++++++---- src/linter/block_linter.go | 58 +++-- src/linter/report.go | 23 +- src/tests/checkers/basic_test.go | 2 + ...alse_safety_test.go => not_safety_test.go} | 154 +++++++++---- src/tests/checkers/null_safety_test.go | 22 ++ src/types/lazy.go | 8 +- src/types/map.go | 37 +++ src/types/predicates.go | 14 ++ src/utils/utils.go | 9 + 10 files changed, 423 insertions(+), 116 deletions(-) rename src/tests/checkers/{false_safety_test.go => not_safety_test.go} (53%) diff --git a/src/linter/block.go b/src/linter/block.go index 1a623928..80818eab 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1038,7 +1038,7 @@ func formatSlashesFuncName(fn meta.FuncInfo) string { return strings.TrimPrefix(fn.Name, "\\") } -func (b *blockWalker) checkNullSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) { +func (b *blockWalker) checkNotSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) { if fn.Params == nil || fn.Name == "" { return } @@ -1056,26 +1056,26 @@ func (b *blockWalker) checkNullSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) switch a := arg.(*ir.Argument).Expr.(type) { case *ir.SimpleVar: - b.checkSimpleVarNullSafety(arg, fn, i, a, haveVariadic) + b.checkSimpleVarSafety(arg, fn, i, a, haveVariadic) case *ir.ConstFetchExpr: - b.checkConstFetchNullSafety(arg, fn, i, a, haveVariadic) + b.checkConstFetchSafety(arg, fn, i, a, haveVariadic) case *ir.ArrayDimFetchExpr: - b.checkArrayDimFetchNullSafety(arg, fn, i, a, haveVariadic) + b.checkArrayDimFetchSafety(arg, fn, i, a, haveVariadic) case *ir.ListExpr: - b.checkListExprNullSafety(arg, fn, i, a, haveVariadic) + b.checkListExprSafety(arg, fn, i, a, haveVariadic) case *ir.PropertyFetchExpr: - b.checkPropertyFetchNullSafety(a, fn, i, haveVariadic) + b.checkPropertyFetchNotSafety(a, fn, i, haveVariadic) case *ir.StaticCallExpr: - b.checkStaticCallNullSafety(arg, fn, i, a, haveVariadic) + b.checkStaticCallSafety(arg, fn, i, a, haveVariadic) case *ir.StaticPropertyFetchExpr: b.checkStaticPropertyFetchNullSafety(a, fn, i, haveVariadic) case *ir.FunctionCallExpr: - b.checkFunctionCallNullSafety(arg, fn, i, a, haveVariadic) + b.checkFunctionCallSafety(arg, fn, i, a, haveVariadic) } } } -func (b *blockWalker) checkFunctionCallNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, funcCall *ir.FunctionCallExpr, haveVariadic bool) { +func (b *blockWalker) checkFunctionCallSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, funcCall *ir.FunctionCallExpr, haveVariadic bool) { var funcName string var isClearF bool @@ -1105,22 +1105,33 @@ func (b *blockWalker) checkFunctionCallNullSafety(arg ir.Node, fn meta.FuncInfo, } param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) + paramType := param.Typ if haveVariadic && paramIndex >= len(fn.Params)-1 { // For variadic parameter check, if type is mixed then skip. - if types.IsTypeMixed(param.Typ) { + if types.IsTypeMixed(paramType) { return } } - paramAllowsNull := types.IsTypeNullable(param.Typ) + paramAllowsNull := types.IsTypeNullable(paramType) varIsNullable := types.IsTypeNullable(callType) if varIsNullable && !paramAllowsNull { b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentFunctionCall", "not null safety call in function %s signature of param %s when calling function %s", formatSlashesFuncName(fn), param.Name, funcInfo.Name) } + + if paramType.Empty() || varIsNullable { + return + } + + if !b.isTypeCompatible(callType, param.Typ) { + b.report(arg, LevelWarning, "notSafetyCall", + "not safety call in function %s signature of param %s when calling function %s", + formatSlashesFuncName(fn), param.Name, funcInfo.Name) + } } -func (b *blockWalker) checkStaticCallNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, staticCallF *ir.StaticCallExpr, haveVariadic bool) { +func (b *blockWalker) checkStaticCallSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, staticCallF *ir.StaticCallExpr, haveVariadic bool) { funcName, ok := staticCallF.Call.(*ir.Identifier) if !ok { return @@ -1149,62 +1160,143 @@ func (b *blockWalker) checkStaticCallNullSafety(arg ir.Node, fn meta.FuncInfo, p } param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) + paramType := param.Typ if haveVariadic && paramIndex >= len(fn.Params)-1 { // For variadic parameter check, if type is mixed then skip. - if types.IsTypeMixed(param.Typ) { + if types.IsTypeMixed(paramType) { return } } - paramAllowsNull := types.IsTypeNullable(param.Typ) - varIsNullable := types.IsTypeNullable(funcInfo.Typ) + funcType := funcInfo.Typ + paramAllowsNull := types.IsTypeNullable(paramType) + varIsNullable := types.IsTypeNullable(funcType) if varIsNullable && !paramAllowsNull { b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentStaticFunctionCall", "not null safety call in function %s signature of param %s when calling static function %s", formatSlashesFuncName(fn), param.Name, funcInfo.Name) } + + if paramType.Empty() || varIsNullable { + return + } + + if !b.isTypeCompatible(funcType, param.Typ) { + b.report(arg, LevelWarning, "notSafetyCall", + "not safety static call in function %s signature of param %s", + formatSlashesFuncName(fn), param.Name) + } } -func (b *blockWalker) checkSimpleVarNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, variable *ir.SimpleVar, haveVariadic bool) { +func (b *blockWalker) checkSimpleVarSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, variable *ir.SimpleVar, haveVariadic bool) { varInfo, ok := b.ctx.sc.GetVar(variable) if !ok { return } param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) + paramType := param.Typ if haveVariadic && paramIndex >= len(fn.Params)-1 { // For variadic parameter check, if type is mixed then skip. - if types.IsTypeMixed(param.Typ) { + if types.IsTypeMixed(paramType) { return } } - paramAllowsNull := types.IsTypeNullable(param.Typ) - varIsNullable := types.IsTypeNullable(varInfo.Type) + paramAllowsNull := types.IsTypeNullable(paramType) + varType := varInfo.Type + varIsNullable := types.IsTypeNullable(varType) if varIsNullable && !paramAllowsNull { b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentVariable", "not null safety call in function %s signature of param %s", formatSlashesFuncName(fn), param.Name) } + + if paramType.Empty() || varIsNullable { + return + } + + if !b.isTypeCompatible(varType, paramType) { + b.report(arg, LevelWarning, "notSafetyCall", + "not safety call in function %s signature of param %s", + formatSlashesFuncName(fn), param.Name) + } } -func (b *blockWalker) checkConstFetchNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, constExpr *ir.ConstFetchExpr, haveVariadic bool) { +func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) bool { + isVarBoolean := varType.IsBoolean() + isClass := varType.IsClass() + varClassName := varType.String() + + if varType.Len() > paramType.Len() { + return false + } + + for _, param := range paramType.Keys() { + // boolean case + if isVarBoolean && (param == "bool" || param == "boolean") { + return true + } + paramType.IsArray() + if paramType.Contains(types.WrapArrayOf("mixed")) || paramType.Contains("mixed") { + return true + } + + // exact match + if varType.Contains(param) { + return true + } + + // class check + if isClass { + if param == "object" || strings.Contains(param, varClassName) { + return true + } + if !types.IsScalar(param) { + if classInfo, ok := b.r.meta.Classes.Get(varClassName); ok { + if utils.ContainsKey(param, classInfo.Interfaces) { + return true + } + if classInfo.Parent != "" && strings.Contains(param, classInfo.Parent) { + return true + } + } + } + } + } + return false +} + +func (b *blockWalker) checkConstFetchSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, constExpr *ir.ConstFetchExpr, haveVariadic bool) { constVal := constExpr.Constant.Value isNull := constVal == "null" param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) + paramType := param.Typ if haveVariadic && paramIndex >= len(fn.Params)-1 { - if types.IsTypeMixed(param.Typ) { + if types.IsTypeMixed(paramType) { return } } - paramAllowsNull := types.IsTypeNullable(param.Typ) - if isNull && !paramAllowsNull { - b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentConstFetch", - "null passed to non-nullable parameter %s in function %s", - param.Name, formatSlashesFuncName(fn)) + paramAllowsNull := types.IsTypeNullable(paramType) + if isNull { + if !paramAllowsNull { + b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentConstFetch", + "null passed to non-nullable parameter %s in function %s", + param.Name, formatSlashesFuncName(fn)) + } + } else { + isBool := constVal == "true" || constVal == "false" + if isBool { + typ := types.NewMap(constVal) + if !b.isTypeCompatible(typ, paramType) { + b.report(arg, LevelWarning, "notSafetyCall", + "potential not safety access in parameter %s of function %s", + param.Name, formatSlashesFuncName(fn)) + } + } } } -func (b *blockWalker) checkArrayDimFetchNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, arrayExpr *ir.ArrayDimFetchExpr, haveVariadic bool) { +func (b *blockWalker) checkArrayDimFetchSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, arrayExpr *ir.ArrayDimFetchExpr, haveVariadic bool) { baseVar, ok := arrayExpr.Variable.(*ir.SimpleVar) if !ok { return @@ -1222,34 +1314,62 @@ func (b *blockWalker) checkArrayDimFetchNullSafety(arg ir.Node, fn meta.FuncInfo } } paramAllowsNull := types.IsTypeNullable(param.Typ) - if types.IsTypeNullable(varInfo.Type) && !paramAllowsNull { + varType := varInfo.Type + varIsNullable := types.IsTypeNullable(varType) + if varIsNullable && !paramAllowsNull { b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentArrayDimFetch", "potential null array access in parameter %s of function %s", param.Name, formatSlashesFuncName(fn)) } + + if param.Typ.Empty() || varIsNullable { + return + } + + if !b.isTypeCompatible(varType, param.Typ) { + b.report(arg, LevelWarning, "notSafetyCall", + "not safety array access in parameter %s of function %s", + param.Name, formatSlashesFuncName(fn)) + } } -func (b *blockWalker) checkListExprNullSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, listExpr *ir.ListExpr, haveVariadic bool) { +func (b *blockWalker) checkListExprSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, listExpr *ir.ListExpr, haveVariadic bool) { for _, item := range listExpr.Items { if item == nil { continue } if item.Key != nil { - b.checkNullSafetyCallArgsF([]ir.Node{item.Key}, fn) + b.checkNotSafetyCallArgsF([]ir.Node{item.Key}, fn) } if item.Val != nil { param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) + paramType := param.Typ if simpleVar, ok := item.Val.(*ir.SimpleVar); ok { varInfo, found := b.ctx.sc.GetVar(simpleVar) - if found && types.IsTypeNullable(varInfo.Type) && !types.IsTypeNullable(param.Typ) { - b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentList", - "potential null value in list assignment for param %s in function %s", - param.Name, formatSlashesFuncName(fn)) + if found { + varType := varInfo.Type + varIsNullable := types.IsTypeNullable(varType) + if varIsNullable && !types.IsTypeNullable(paramType) { + { + b.report(arg, LevelWarning, "notNullSafetyFunctionArgumentList", + "potential null value in list assignment for param %s in function %s", + param.Name, formatSlashesFuncName(fn)) + } + } + if paramType.Empty() || varIsNullable { + return + } + + if !b.isTypeCompatible(varType, paramType) { + b.report(arg, LevelWarning, "notSafetyCall", + "potential not safety list assignment for param %s in function %s", + param.Name, formatSlashesFuncName(fn)) + } } } - b.checkNullSafetyCallArgsF([]ir.Node{item.Val}, fn) + b.checkNotSafetyCallArgsF([]ir.Node{item.Val}, fn) } } } @@ -1303,10 +1423,10 @@ func (b *blockWalker) getPropertyComputedType(expr ir.Node) (meta.ClassInfo, typ } } -func (b *blockWalker) checkPropertyFetchNullSafety(expr *ir.PropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { +func (b *blockWalker) checkPropertyFetchNotSafety(expr *ir.PropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { // Recursively check the left part of the chain if it is also a property fetch. if nested, ok := expr.Variable.(*ir.PropertyFetchExpr); ok { - b.checkPropertyFetchNullSafety(nested, fn, paramIndex, haveVariadic) + b.checkPropertyFetchNotSafety(nested, fn, paramIndex, haveVariadic) } classInfo, propType := b.getPropertyComputedType(expr) @@ -1332,11 +1452,12 @@ func (b *blockWalker) checkingPropertyFetchNullSafetyCondition( ) { isPrpNullable := types.IsTypeNullable(propType) param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) + paramType := param.Typ if haveVariadic && paramIndex >= len(fn.Params)-1 { - if types.IsTypeMixed(param.Typ) { + if types.IsTypeMixed(paramType) { return } - paramAllowsNull := types.IsTypeNullable(param.Typ) + paramAllowsNull := types.IsTypeNullable(paramType) if isPrpNullable && !paramAllowsNull { b.report(expr, LevelWarning, "notNullSafetyFunctionArgumentPropertyFetch", "potential null dereference when accessing property '%s'", prpName) @@ -1344,11 +1465,20 @@ func (b *blockWalker) checkingPropertyFetchNullSafetyCondition( return } - paramAllowsNull := types.IsTypeNullable(param.Typ) + paramAllowsNull := types.IsTypeNullable(paramType) if isPrpNullable && !paramAllowsNull { b.report(expr, LevelWarning, "notNullSafetyFunctionArgumentPropertyFetch", "potential null dereference when accessing property '%s'", prpName) } + + if paramType.Empty() || isPrpNullable { + return + } + + if !b.isTypeCompatible(propType, paramType) { + b.report(expr, LevelWarning, "notSafetyCall", + "potential not safety accessing property '%s'", prpName) + } } func (b *blockWalker) checkStaticPropertyFetchNullSafety(expr *ir.StaticPropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { @@ -1371,7 +1501,7 @@ func (b *blockWalker) checkStaticPropertyFetchNullSafety(expr *ir.StaticProperty } func (b *blockWalker) handleCallArgs(args []ir.Node, fn meta.FuncInfo) { - b.checkNullSafetyCallArgsF(args, fn) + b.checkNotSafetyCallArgsF(args, fn) for i, arg := range args { if i >= len(fn.Params) { diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 96ac4a49..9cfc4c27 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -601,10 +601,14 @@ func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { parseState := b.classParseState() left, ok := parseState.Info.GetVarType(v.Class) - if ok && left.Contains("null") { - b.report(s, LevelWarning, "notNullSafetyPropertyFetch", - "potential null dereference when accessing static property") + /* if ok && left.Contains("null") { + b.report(s, LevelWarning, "notNullSafetyPropertyFetch", + "potential null dereference when accessing static property") + }*/ + if ok { + b.checkSafetyCall(s, left, "", "PropertyFetch") } + } return } @@ -1343,14 +1347,14 @@ func (b *blockLinter) checkMethodCall(e *ir.MethodCallExpr) { funInfo, found := parseState.Info.GetFunction(funcName) if found { funcType := funInfo.Typ - b.checkSafetyMethodCall(e, funcType, funInfo.Name, "FunctionCall") + b.checkSafetyCall(e, funcType, funInfo.Name, "FunctionCall") } } case *ir.SimpleVar: varType, ok := b.walker.ctx.sc.GetVarType(caller) if ok { - b.checkSafetyMethodCall(e, varType, caller.Name, "Variable") + b.checkSafetyCall(e, varType, caller.Name, "Variable") } } @@ -1371,15 +1375,37 @@ func (b *blockLinter) checkMethodCall(e *ir.MethodCallExpr) { } } -func (b *blockLinter) checkSafetyMethodCall(e *ir.MethodCallExpr, typ types.Map, name string, suffix string) { +func (b *blockLinter) checkSafetyCall(e ir.Node, typ types.Map, name string, suffix string) { if typ.Contains("null") { - b.report(e, LevelWarning, "notNullSafety"+suffix, - "potential null dereference in %s when accessing method", name) + reportFullName := "notNullSafety" + suffix + switch { + case reportFullName == "notNullSafetyPropertyFetch": + b.report(e, LevelWarning, "notNullSafety"+suffix, + "attempt to access property that can be null") + case reportFullName == "notNullSafetyVariable" || reportFullName == "notNullSafetyFunctionCall": + b.report(e, LevelWarning, reportFullName, + "potential null dereference in %s when accessing method", name) + } + } - if typ.Contains("false") { + + isSafetyCall := true + typ.Iterate(func(typ string) { + if types.IsScalar(typ) { + isSafetyCall = false + } + }) + + if !isSafetyCall { + b.report(e, LevelWarning, "notSafetyCall", + "potential not safety call in %s when accessing method", name) + } + + // TODO: delete after ^ + /* if typ.Contains("false") { b.report(e, LevelWarning, "notFalseSafety"+suffix, "potential false in %s when accessing method", name) - } + }*/ } func (b *blockLinter) checkStaticCall(e *ir.StaticCallExpr) { @@ -1476,9 +1502,15 @@ func (b *blockLinter) checkPropertyFetch(e *ir.PropertyFetchExpr) { } left, ok := globalMetaInfo.Info.GetVarType(e.Variable) - if ok && left.Contains("null") { - b.report(e, LevelWarning, "notNullSafetyPropertyFetch", - "attempt to access property that can be null") + if ok { + /* if left.Contains("null") { + b.checkSafetyCall(e, left, "", "PropertyFetch") + b.report(e, LevelWarning, "notNullSafetyPropertyFetch", + "attempt to access property that can be null") + }*/ + b.checkSafetyCall(e, left, "", "PropertyFetch") + //b.checkSafetyCall(e, left, "", "PropertyFetch") + } } diff --git a/src/linter/report.go b/src/linter/report.go index c8c71f0d..9d3bfaaa 100644 --- a/src/linter/report.go +++ b/src/linter/report.go @@ -26,10 +26,10 @@ func addBuiltinCheckers(reg *CheckersRegistry) { }, { - Name: "notFalseSafetyFunctionCall", + Name: "notSafetyCall", Default: true, Quickfix: false, - Comment: "Report not false-safety call", + Comment: "Report not safety call", Before: `/** * @return User|false */ @@ -38,24 +38,7 @@ function getUser():User|false { } $a = getUser()->do(); `, - After: `reported not false-safety call`, - }, - - { - Name: "notFalseSafetyVariable", - Default: true, - Quickfix: false, - Comment: "Report not false-safety call", - Before: `/** - * @return User|false - */ -function getUser():User|false { - return null; -} -$a = getUser(); -$b = $a->do(); -`, - After: `reported not false-safety call`, + After: `reported not safety call`, }, { diff --git a/src/tests/checkers/basic_test.go b/src/tests/checkers/basic_test.go index d4dad7c6..a0e17e67 100644 --- a/src/tests/checkers/basic_test.go +++ b/src/tests/checkers/basic_test.go @@ -2217,6 +2217,8 @@ function f() { `possibly wrong order of arguments, min = 100, max = 99`, `possibly wrong order of arguments, min = 1, max = 0`, `possibly wrong order of arguments, min = 156, max = 119`, + `potential not safety access in parameter min of function random_int`, + `potential not safety access in parameter max of function random_int`, } test.RunAndMatch() } diff --git a/src/tests/checkers/false_safety_test.go b/src/tests/checkers/not_safety_test.go similarity index 53% rename from src/tests/checkers/false_safety_test.go rename to src/tests/checkers/not_safety_test.go index 7216981e..3ca0932f 100644 --- a/src/tests/checkers/false_safety_test.go +++ b/src/tests/checkers/not_safety_test.go @@ -15,7 +15,7 @@ $var = false; test($var); `) test.Expect = []string{ - "false passed to non-falseable parameter s in function test", + "not safety call in function test signature of param", } test.RunAndMatch() } @@ -29,79 +29,73 @@ function test(string $s): void { test(false); `) test.Expect = []string{ - "false passed to non-falseable parameter s in function test", + "potential not safety access in parameter s of function test", } test.RunAndMatch() } -func TestFunctionPassingFalse_ArrayDimFetch(t *testing.T) { +func TestFunctionPassingArrayDimFetch(t *testing.T) { test := linttest.NewSuite(t) test.AddFile(`prop); +$arr = [false]; +test($arr[0]); `) - test.Expect = []string{ - "false passed to non-falseable parameter s in function test", - } + test.Expect = []string{} test.RunAndMatch() } -func TestFunctionPassingFalse_StaticCall(t *testing.T) { +func TestFunctionPassingListExprUnpack(t *testing.T) { test := linttest.NewSuite(t) test.AddFile(`do(); } else{ -$a = $b->do(); +$с = $b->do(); } `) test.Expect = []string{ "Missing PHPDoc for \\User::do public method", "Call to undefined method", - "potential false in b when accessing method", - "Duplicated if/else actions", + "potential not safety call in b when accessing method", } test.RunAndMatch() } @@ -217,7 +210,88 @@ $a = getUser()->do(); `) test.Expect = []string{ "Missing PHPDoc for \\User::do public method", - "potential false in \\getUser when accessing method", + "potential not safety call in \\getUser when accessing method", + } + test.RunAndMatch() +} + +func TestFalseParamInFunc(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`value; +} + +$a = new A(); +test($a->b); +`) + test.Expect = []string{ + "potential not safety accessing property 'b'", } test.RunAndMatch() } diff --git a/src/tests/checkers/null_safety_test.go b/src/tests/checkers/null_safety_test.go index c18e537a..06c8db99 100644 --- a/src/tests/checkers/null_safety_test.go +++ b/src/tests/checkers/null_safety_test.go @@ -369,6 +369,28 @@ test(A::hello()); test.RunAndMatch() } +func TestFuncCallNullSafety(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(` stringLenBytes+1 { + return s[stringLenBytes+1:] + } + + return "" } func unwrap2(s string) (one, two string) { diff --git a/src/types/map.go b/src/types/map.go index f942d81b..73a1abf2 100644 --- a/src/types/map.go +++ b/src/types/map.go @@ -122,6 +122,14 @@ func NewMap(str string) Map { return Map{m: m} } +func (m Map) Keys() []string { + keys := make([]string, 0, len(m.m)) + for k := range m.m { + keys = append(keys, k) + } + return keys +} + func NewPreciseMap(str string) Map { m := NewMap(str) m.flags |= mapPrecise @@ -224,6 +232,35 @@ func (m Map) IsArray() bool { return false } +func (m Map) IsClass() bool { + if len(m.m) != 1 { + return false + } + for typ := range m.m { + potentialClassIndex := strings.Index(typ, "\\") + if potentialClassIndex != -1 { + return IsClass(typ[potentialClassIndex:]) + } + } + return false +} + +func (m Map) IsBoolean() bool { + if len(m.m) != 1 { + return false + } + + // we can have type with flags like 0400bool + for typ := range m.m { + if UnwrapElemOf(typ) == "bool" || strings.HasSuffix(typ, "bool") || + strings.HasSuffix(typ, "true") || + strings.HasSuffix(typ, "false") { + return true + } + } + return false +} + // Is reports whether m contains exactly one specified type. // // Warning: typ must be a proper *lazy* or *solved* type. diff --git a/src/types/predicates.go b/src/types/predicates.go index 3c7b2848..56d330cc 100644 --- a/src/types/predicates.go +++ b/src/types/predicates.go @@ -32,6 +32,10 @@ func IsTrivial(s string) bool { return trivial[s] } +func IsScalar(s string) bool { + return scalar[s] +} + func IsAlias(s string) bool { _, has := aliases[s] return has @@ -81,6 +85,16 @@ var trivial = map[string]bool{ "false": true, } +var scalar = map[string]bool{ + "bool": true, + "float": true, + "int": true, + "string": true, + + "true": true, + "false": true, +} + var aliases = map[string]string{ "integer": "int", "long": "int", diff --git a/src/utils/utils.go b/src/utils/utils.go index 72db34b8..3a9ac6de 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -40,6 +40,15 @@ func NameNodeEquals(n ir.Node, s string) bool { } } +func ContainsKey(param string, m map[string]struct{}) bool { + for k := range m { + if strings.Contains(param, k) { + return true + } + } + return false +} + // IsSpecialClassName checks if the passed node is a special class name. func IsSpecialClassName(n ir.Node) bool { name := NameNodeToString(n) From 25c97f06b76c0fe2676cd426bb163df87b4b1b2c Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Sun, 30 Mar 2025 23:52:44 +0300 Subject: [PATCH 18/36] better inferring for type by is_ condition --- src/linter/and_walker.go | 73 ++++++++++++++++++++++++++- src/linter/block_linter.go | 6 ++- src/tests/checkers/not_safety_test.go | 26 ++++++++++ src/tests/checkers/oop_test.go | 5 ++ src/types/map.go | 30 +++++++++++ src/types/predicates.go | 1 + 6 files changed, 138 insertions(+), 3 deletions(-) diff --git a/src/linter/and_walker.go b/src/linter/and_walker.go index 393f22d6..f353e465 100644 --- a/src/linter/and_walker.go +++ b/src/linter/and_walker.go @@ -72,6 +72,23 @@ func (a *andWalker) EnterNode(w ir.Node) (res bool) { } } + switch { + case nm.Value == `is_int`: + a.handleTypeCheckCondition("int", n.Args) + case nm.Value == `is_float`: + a.handleTypeCheckCondition("float", n.Args) + case nm.Value == `is_string`: + a.handleTypeCheckCondition("string", n.Args) + case nm.Value == `is_object`: + a.handleTypeCheckCondition("object", n.Args) + case nm.Value == `is_array`: + a.handleTypeCheckCondition("array", n.Args) + case nm.Value == `is_null`: + a.handleTypeCheckCondition("null", n.Args) + case nm.Value == `is_resource`: + a.handleTypeCheckCondition("resource", n.Args) + } + case *ir.BooleanAndExpr: a.path.Push(n) n.Left.Walk(a) @@ -227,6 +244,60 @@ func (a *andWalker) EnterNode(w ir.Node) (res bool) { return res } +func (a *andWalker) handleTypeCheckCondition(expectedType string, args []ir.Node) { + for _, arg := range args { + argument, ok := arg.(*ir.Argument) + if !ok { + continue + } + variable, ok := argument.Expr.(*ir.SimpleVar) + if !ok { + continue + } + + // We need to traverse the variable here to check that + // it exists, since this variable will be added to the + // context later. + a.b.handleVariable(variable) + + currentType := a.exprType(variable) + + if a.inNot { + currentType = a.exprTypeInContext(a.trueContext, variable) + } else { + currentType = a.exprTypeInContext(a.falseContext, variable) + } + + var trueType, falseType types.Map + + if expectedType == "bool" { + // we can have false/true/bool as type that's why we should check all situation + boolUnion := types.NewMap("bool").Union(types.NewMap("true")).Union(types.NewMap("false")) + intersection := currentType.Intersect(boolUnion) + if intersection.Empty() { + // If there is no explicit bool subtype, then the positive branch becomes simply "bool" + trueType = types.NewMap("bool") + } else { + // Otherwise, we leave exactly those literals that were in the current type + trueType = intersection + } + // Negative branch - remove all bool subtypes + falseType = currentType.Clone().Erase("bool").Erase("true").Erase("false") + } else { + // For other types, standard logic + trueType = types.NewMap(expectedType) + falseType = currentType.Clone().Erase(expectedType) + } + + if a.inNot { + trueType, falseType = falseType, trueType + } + + a.trueContext.sc.ReplaceVar(variable, trueType, "type narrowing for "+expectedType, meta.VarAlwaysDefined) + a.falseContext.sc.ReplaceVar(variable, falseType, "type narrowing for "+expectedType, meta.VarAlwaysDefined) + } +} + func (a *andWalker) handleConditionSafety(left ir.Node, right ir.Node, identical bool) { variable, ok := left.(*ir.SimpleVar) if !ok { @@ -243,7 +314,7 @@ func (a *andWalker) handleConditionSafety(left ir.Node, right ir.Node, identical // context later. a.b.handleVariable(variable) - currentVar, isGotVar := a.trueContext.sc.GetVar(variable) + currentVar, isGotVar := a.b.ctx.sc.GetVar(variable) if !isGotVar { return } diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 0fa64ba6..78474641 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -1404,15 +1404,17 @@ func (b *blockLinter) checkSafetyCall(e ir.Node, typ types.Map, name string, suf case reportFullName == "notNullSafetyPropertyFetch": b.report(e, LevelWarning, "notNullSafety"+suffix, "attempt to access property that can be null") + return case reportFullName == "notNullSafetyVariable" || reportFullName == "notNullSafetyFunctionCall": b.report(e, LevelWarning, reportFullName, "potential null dereference in %s when accessing method", name) + return } - } isSafetyCall := true typ.Iterate(func(typ string) { + // TODO: here we can problem with mixed: $xs = [0, new Foo()]; $foo = $xs[0]; <== mixed. Need fix for array elem if types.IsScalar(typ) { isSafetyCall = false } @@ -1517,7 +1519,7 @@ 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) } - left, ok := globalMetaInfo.Info.GetVarType(e.Variable) + left, ok := b.walker.ctx.sc.GetVarType(e.Variable) if ok { b.checkSafetyCall(e, left, "", "PropertyFetch") } diff --git a/src/tests/checkers/not_safety_test.go b/src/tests/checkers/not_safety_test.go index 3ca0932f..605570f7 100644 --- a/src/tests/checkers/not_safety_test.go +++ b/src/tests/checkers/not_safety_test.go @@ -295,3 +295,29 @@ test($a->b); } test.RunAndMatch() } + +func TestIsCondition(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`name; +} else{ +$b = $x->name; +} +`) + test.Expect = []string{ + "Call to undefined function is_int", + "Property {int}->name does not exist", + "potential not safety call in when accessing method", + } + test.RunAndMatch() +} diff --git a/src/tests/checkers/oop_test.go b/src/tests/checkers/oop_test.go index 7e6a4988..1fa4e37e 100644 --- a/src/tests/checkers/oop_test.go +++ b/src/tests/checkers/oop_test.go @@ -289,6 +289,7 @@ $_ = WithProps::$int; test.Expect = []string{ `Class constant \WithProps::int does not exist`, `Property \WithProps::$int does not exist`, + `attempt to access property that can be null`, } test.RunAndMatch() @@ -347,6 +348,8 @@ $_ = WithProps::$int1; `Class constant \WithProps::int1 does not exist`, `Property \WithProps::$int does not exist`, `Property \WithProps::$int1 does not exist`, + `attempt to access property that can be null`, + `attempt to access property that can be null`, } test.RunAndMatch() @@ -1111,6 +1114,8 @@ function test3(?A $instance) { `) test.Expect = []string{ `Property {\A|null}->c does not exist`, + `attempt to access property that can be null`, + `attempt to access property that can be null`, } test.RunAndMatch() } diff --git a/src/types/map.go b/src/types/map.go index 73a1abf2..c1996a44 100644 --- a/src/types/map.go +++ b/src/types/map.go @@ -188,6 +188,36 @@ func (m Map) Equals(m2 Map) bool { return true } +// Union return new Map that contains all types from the current and other +func (m Map) Union(other Map) Map { + result := make(map[string]struct{}, len(m.m)+len(other.m)) + for k := range m.m { + result[k] = struct{}{} + } + for k := range other.m { + result[k] = struct{}{} + } + + return Map{ + flags: m.flags, + m: result, + } +} + +// Intersect return new Map that contains only intersect types +func (m Map) Intersect(other Map) Map { + result := make(map[string]struct{}) + for k := range m.m { + if _, ok := other.m[k]; ok { + result[k] = struct{}{} + } + } + return Map{ + flags: m.flags, + m: result, + } +} + // Len returns number of different types in map func (m Map) Len() int { return len(m.m) diff --git a/src/types/predicates.go b/src/types/predicates.go index 56d330cc..98fec14b 100644 --- a/src/types/predicates.go +++ b/src/types/predicates.go @@ -93,6 +93,7 @@ var scalar = map[string]bool{ "true": true, "false": true, + //"mixed": true, } var aliases = map[string]string{ From c6c641c5f1ce84fd765ad8a8e25993c1335b3818 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Mon, 31 Mar 2025 14:55:52 +0300 Subject: [PATCH 19/36] test fix stubs --- src/linttest/linttest.go | 7 ++++--- src/tests/checkers/basic_test.go | 1 + src/tests/checkers/not_safety_test.go | 1 - 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/linttest/linttest.go b/src/linttest/linttest.go index fc968b52..12219e8f 100644 --- a/src/linttest/linttest.go +++ b/src/linttest/linttest.go @@ -107,9 +107,10 @@ func newSuite(t testing.TB, ver string) *Suite { return &Suite{ t: t, defaultStubs: map[string]struct{}{ - `stubs/phpstorm-stubs/Core/Core.php`: {}, - `stubs/phpstorm-stubs/Core/Core_c.php`: {}, - `stubs/phpstorm-stubs/Core/Core_d.php`: {}, + `stubs/phpstorm-stubs/Core/Core.php`: {}, + `stubs/phpstorm-stubs/Core/Core_c.php`: {}, + `stubs/phpstorm-stubs/Core/Core_d.php`: {}, + `stubs/phpstorm-stubs/standard/standard_5.php`: {}, }, ignoreUndeclaredChecks: false, config: conf, diff --git a/src/tests/checkers/basic_test.go b/src/tests/checkers/basic_test.go index 14785fb0..e414d1db 100644 --- a/src/tests/checkers/basic_test.go +++ b/src/tests/checkers/basic_test.go @@ -2147,6 +2147,7 @@ function f() { `Use float cast instead of real`, `Use is_float function instead of is_real`, `Use is_float instead of 'is_real`, + `Call to deprecated function is_real (since: 7.4)`, } test.RunAndMatch() } diff --git a/src/tests/checkers/not_safety_test.go b/src/tests/checkers/not_safety_test.go index 605570f7..d36d90ba 100644 --- a/src/tests/checkers/not_safety_test.go +++ b/src/tests/checkers/not_safety_test.go @@ -315,7 +315,6 @@ $b = $x->name; } `) test.Expect = []string{ - "Call to undefined function is_int", "Property {int}->name does not exist", "potential not safety call in when accessing method", } From 71749ccafbe656370b8d22466e15f4438c70df3a Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Mon, 31 Mar 2025 15:05:34 +0300 Subject: [PATCH 20/36] updated stubs --- src/linttest/linttest.go | 9 +++++++++ src/tests/checkers/null_safety_test.go | 1 - src/tests/checkers/php_aliases_test.go | 3 --- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/linttest/linttest.go b/src/linttest/linttest.go index 12219e8f..9dc09a3d 100644 --- a/src/linttest/linttest.go +++ b/src/linttest/linttest.go @@ -110,7 +110,16 @@ func newSuite(t testing.TB, ver string) *Suite { `stubs/phpstorm-stubs/Core/Core.php`: {}, `stubs/phpstorm-stubs/Core/Core_c.php`: {}, `stubs/phpstorm-stubs/Core/Core_d.php`: {}, + `stubs/phpstorm-stubs/standard/standard_0.php`: {}, + `stubs/phpstorm-stubs/standard/standard_1.php`: {}, + `stubs/phpstorm-stubs/standard/standard_2.php`: {}, + `stubs/phpstorm-stubs/standard/standard_3.php`: {}, + `stubs/phpstorm-stubs/standard/standard_4.php`: {}, `stubs/phpstorm-stubs/standard/standard_5.php`: {}, + `stubs/phpstorm-stubs/standard/standard_6.php`: {}, + `stubs/phpstorm-stubs/standard/standard_7.php`: {}, + `stubs/phpstorm-stubs/standard/standard_8.php`: {}, + `stubs/phpstorm-stubs/standard/standard_9.php`: {}, }, ignoreUndeclaredChecks: false, config: conf, diff --git a/src/tests/checkers/null_safety_test.go b/src/tests/checkers/null_safety_test.go index 06c8db99..ba5159f3 100644 --- a/src/tests/checkers/null_safety_test.go +++ b/src/tests/checkers/null_safety_test.go @@ -262,7 +262,6 @@ echo $maybeClass::$value; `) test.Expect = []string{ "Missing PHPDoc for \\A::hello public method", - "Call to undefined function rand", "potential null dereference when accessing static call throw $maybeClass", "attempt to access property that can be null", } diff --git a/src/tests/checkers/php_aliases_test.go b/src/tests/checkers/php_aliases_test.go index 6fba1a8b..7c4124f1 100644 --- a/src/tests/checkers/php_aliases_test.go +++ b/src/tests/checkers/php_aliases_test.go @@ -13,7 +13,6 @@ declare(strict_types = "1") $_ = join("", []); `) test.Expect = []string{ - `Call to undefined function join`, `Use implode instead of 'join'`, } test.RunAndMatch() @@ -35,9 +34,7 @@ test(join("", [])); `Use OCICollection::max instead of 'ocicollmax'`, `Call to undefined function ocicollmax`, `Use implode instead of 'join'`, - `Call to undefined function join`, `Use implode instead of 'join'`, - `Call to undefined function join`, } test.RunAndMatch() } From f7d65362aa21b64d309c1b6ebd50860c52cb440f Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Mon, 31 Mar 2025 17:56:25 +0300 Subject: [PATCH 21/36] logic for is_object and test --- src/linter/and_walker.go | 25 +++++++++++++++++++++++++ src/linter/block_linter.go | 5 +++++ src/linttest/golden_linttest.go | 16 ++++++++++++++-- src/tests/checkers/not_safety_test.go | 27 ++++++++++++++++++++++++++- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/linter/and_walker.go b/src/linter/and_walker.go index f353e465..983e0168 100644 --- a/src/linter/and_walker.go +++ b/src/linter/and_walker.go @@ -283,6 +283,31 @@ func (a *andWalker) handleTypeCheckCondition(expectedType string, args []ir.Node } // Negative branch - remove all bool subtypes falseType = currentType.Clone().Erase("bool").Erase("true").Erase("false") + } else if expectedType == "object" { + // For is_object: keys that is not primitives + keys := currentType.Keys() + var objectKeys []string + for _, k := range keys { + switch k { + case "int", "float", "string", "bool", "null", "true", "false", "mixed", "callable", "resource", "void", "iterable", "never": + // skip not object + continue + default: + objectKeys = append(objectKeys, k) + } + } + if len(objectKeys) == 0 { + trueType = types.NewMap("object") + } else { + trueType = types.NewEmptyMap(1) + for _, k := range objectKeys { + trueType = trueType.Union(types.NewMap(k)) + } + } + falseType = currentType.Clone() + for _, k := range objectKeys { + falseType = falseType.Erase(k) + } } else { // For other types, standard logic trueType = types.NewMap(expectedType) diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 78474641..71956663 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -1421,6 +1421,11 @@ func (b *blockLinter) checkSafetyCall(e ir.Node, typ types.Map, name string, suf }) if !isSafetyCall { + if name == "" { + b.report(e, LevelWarning, "notSafetyCall", + "potential not safety call when accessing property") + return + } b.report(e, LevelWarning, "notSafetyCall", "potential not safety call in %s when accessing method", name) } diff --git a/src/linttest/golden_linttest.go b/src/linttest/golden_linttest.go index d27ed7bf..95941d76 100644 --- a/src/linttest/golden_linttest.go +++ b/src/linttest/golden_linttest.go @@ -4,12 +4,14 @@ import ( "encoding/json" "fmt" "log" + "math/rand" "os" "os/exec" "path/filepath" "sort" "strings" "testing" + "time" "github.com/google/go-cmp/cmp" @@ -163,10 +165,20 @@ func (s *GoldenTestSuite) checkGoldenOutput(want []byte, reports []*linter.Repor if diff := cmp.Diff(wantLines, haveLines); diff != "" { s.suite.t.Errorf("results mismatch (+ have) (- want): %s", diff) - // Use fmt.Printf() instead of t.Logf() to make the output - // more copy/paste friendly. fmt.Printf("have:\n%s", strings.Join(haveLines, "\n")) fmt.Printf("want:\n%s", want) + + // Генерируем случайное имя файла + rand.Seed(time.Now().UnixNano()) + fileName := fmt.Sprintf("golden_%d.txt", rand.Intn(1000000)) + filePath := filepath.Join("/Users/r.kuchinskas/Desktop/reportOut", fileName) + + // Записываем `want` в файл + if err := os.WriteFile(filePath, []byte(strings.Join(haveLines, "\n")), 0644); err != nil { + fmt.Printf("failed to write golden file: %v\n", err) + } else { + fmt.Printf("golden file saved: %s\n", filePath) + } } } diff --git a/src/tests/checkers/not_safety_test.go b/src/tests/checkers/not_safety_test.go index d36d90ba..c9e26b34 100644 --- a/src/tests/checkers/not_safety_test.go +++ b/src/tests/checkers/not_safety_test.go @@ -316,7 +316,32 @@ $b = $x->name; `) test.Expect = []string{ "Property {int}->name does not exist", - "potential not safety call in when accessing method", + "potential not safety call when accessing property", + } + test.RunAndMatch() +} + +func TestIsObjectCondition(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`name; +} else{ +$b = $x->name; +} +`) + test.Expect = []string{ + "Property {int}->name does not exist", + "potential not safety call when accessing property", } test.RunAndMatch() } From f1a51748b27d4bd1cde3a95a7789b03b5c7b7aef Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 1 Apr 2025 01:12:28 +0300 Subject: [PATCH 22/36] revert --- src/linttest/golden_linttest.go | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/linttest/golden_linttest.go b/src/linttest/golden_linttest.go index 95941d76..bfa14a13 100644 --- a/src/linttest/golden_linttest.go +++ b/src/linttest/golden_linttest.go @@ -3,17 +3,14 @@ package linttest import ( "encoding/json" "fmt" + "github.com/google/go-cmp/cmp" "log" - "math/rand" "os" "os/exec" "path/filepath" "sort" "strings" "testing" - "time" - - "github.com/google/go-cmp/cmp" "github.com/VKCOM/noverify/src/cmd" "github.com/VKCOM/noverify/src/linter" @@ -165,20 +162,10 @@ func (s *GoldenTestSuite) checkGoldenOutput(want []byte, reports []*linter.Repor if diff := cmp.Diff(wantLines, haveLines); diff != "" { s.suite.t.Errorf("results mismatch (+ have) (- want): %s", diff) + // Use fmt.Printf() instead of t.Logf() to make the output + // more copy/paste friendly. fmt.Printf("have:\n%s", strings.Join(haveLines, "\n")) fmt.Printf("want:\n%s", want) - - // Генерируем случайное имя файла - rand.Seed(time.Now().UnixNano()) - fileName := fmt.Sprintf("golden_%d.txt", rand.Intn(1000000)) - filePath := filepath.Join("/Users/r.kuchinskas/Desktop/reportOut", fileName) - - // Записываем `want` в файл - if err := os.WriteFile(filePath, []byte(strings.Join(haveLines, "\n")), 0644); err != nil { - fmt.Printf("failed to write golden file: %v\n", err) - } else { - fmt.Printf("golden file saved: %s\n", filePath) - } } } From f32a992c63df2bae4317b07bb5e7c221d51cdd75 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 1 Apr 2025 02:43:36 +0300 Subject: [PATCH 23/36] inherit doc type support --- src/linter/block.go | 30 ++++++++----- src/solver/solver.go | 12 +++++ src/tests/checkers/not_safety_test.go | 63 +++++++++++++++++++++++++++ src/types/map.go | 10 ++--- 4 files changed, 96 insertions(+), 19 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index 80818eab..d6ffc4db 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1222,20 +1222,20 @@ func (b *blockWalker) checkSimpleVarSafety(arg ir.Node, fn meta.FuncInfo, paramI } func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) bool { - isVarBoolean := varType.IsBoolean() - isClass := varType.IsClass() - varClassName := varType.String() - if varType.Len() > paramType.Len() { return false } + isVarBoolean := varType.IsBoolean() + isClass := varType.IsClass() + varClassName := varType.String() + for _, param := range paramType.Keys() { // boolean case if isVarBoolean && (param == "bool" || param == "boolean") { return true } - paramType.IsArray() + if paramType.Contains(types.WrapArrayOf("mixed")) || paramType.Contains("mixed") { return true } @@ -1251,17 +1251,23 @@ func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) b return true } if !types.IsScalar(param) { - if classInfo, ok := b.r.meta.Classes.Get(varClassName); ok { - if utils.ContainsKey(param, classInfo.Interfaces) { - return true - } - if classInfo.Parent != "" && strings.Contains(param, classInfo.Parent) { - return true - } + metaInfo := b.r.metaInfo() + if solver.Implements(metaInfo, varClassName, param) { + return true + } else if solver.ImplementsAbstract(metaInfo, varClassName, param) { + return true } } } } + + forcedVartype := types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", varType, solver.ResolverMap{})) + forcedParamType := types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", paramType, solver.ResolverMap{})) + + if !forcedParamType.Intersect(forcedVartype).Empty() { + return true + } + return false } diff --git a/src/solver/solver.go b/src/solver/solver.go index db7a712d..cc9b4ed4 100644 --- a/src/solver/solver.go +++ b/src/solver/solver.go @@ -490,6 +490,18 @@ func Implements(info *meta.Info, className, interfaceName string) bool { return implements(info, className, interfaceName, visited) } +func ImplementsAbstract(info *meta.Info, className, abstractName string) bool { + classInfo, got := info.GetClass(className) + if !got { + return false + } + if classInfo.Parent != "" && strings.Contains(abstractName, classInfo.Parent) { + return true + } + + return false +} + func implements(info *meta.Info, className, interfaceName string, visited map[string]struct{}) bool { if className == interfaceName { return true diff --git a/src/tests/checkers/not_safety_test.go b/src/tests/checkers/not_safety_test.go index c9e26b34..7ee49718 100644 --- a/src/tests/checkers/not_safety_test.go +++ b/src/tests/checkers/not_safety_test.go @@ -345,3 +345,66 @@ $b = $x->name; } test.RunAndMatch() } + +func TestInheritDoc(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`getAdapter()->has($path); + } + + /** + * Assert a file is present. + * + * @param string $path path to file + * + * @throws FileNotFoundException + * + * @return void + */ + public function assertPresent($path) + { + if ($this->config->get('disable_asserts', false) === false && ! $this->has($path)) { + } + } + } +`) + test.Expect = []string{ + "Call to undefined method {\\Filesystem}->getAdapter()", + "Property {\\Filesystem}->config does not exist", + } + test.RunAndMatch() +} diff --git a/src/types/map.go b/src/types/map.go index c1996a44..dafe8f3b 100644 --- a/src/types/map.go +++ b/src/types/map.go @@ -266,13 +266,9 @@ func (m Map) IsClass() bool { if len(m.m) != 1 { return false } - for typ := range m.m { - potentialClassIndex := strings.Index(typ, "\\") - if potentialClassIndex != -1 { - return IsClass(typ[potentialClassIndex:]) - } - } - return false + typ := m.String() + + return strings.HasPrefix(typ, `\`) && !IsShape(typ) && !IsArray(typ) && !IsClosure(typ) && !IsScalar(typ) } func (m Map) IsBoolean() bool { From a94e2251332c6028e43acee453c3a852d05f0b26 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 1 Apr 2025 04:37:45 +0300 Subject: [PATCH 24/36] refactoring and type forcing improving --- src/linter/block.go | 23 +++++++++++++++-------- src/tests/checkers/not_safety_test.go | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index d6ffc4db..8761c220 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1126,7 +1126,7 @@ func (b *blockWalker) checkFunctionCallSafety(arg ir.Node, fn meta.FuncInfo, par if !b.isTypeCompatible(callType, param.Typ) { b.report(arg, LevelWarning, "notSafetyCall", - "not safety call in function %s signature of param %s when calling function %s", + "potential not safety call in function %s signature of param %s when calling function %s", formatSlashesFuncName(fn), param.Name, funcInfo.Name) } } @@ -1182,7 +1182,7 @@ func (b *blockWalker) checkStaticCallSafety(arg ir.Node, fn meta.FuncInfo, param if !b.isTypeCompatible(funcType, param.Typ) { b.report(arg, LevelWarning, "notSafetyCall", - "not safety static call in function %s signature of param %s", + "potential not safety static call in function %s signature of param %s", formatSlashesFuncName(fn), param.Name) } } @@ -1216,14 +1216,20 @@ func (b *blockWalker) checkSimpleVarSafety(arg ir.Node, fn meta.FuncInfo, paramI if !b.isTypeCompatible(varType, paramType) { b.report(arg, LevelWarning, "notSafetyCall", - "not safety call in function %s signature of param %s", + "potential not safety call in function %s signature of param %s", formatSlashesFuncName(fn), param.Name) } } func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) bool { + var forcedVarType types.Map + if varType.Len() > paramType.Len() { - return false + forcedVarType = types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", varType, solver.ResolverMap{})) + if forcedVarType.Len() > paramType.Len() { + return false + } + varType = forcedVarType } isVarBoolean := varType.IsBoolean() @@ -1261,10 +1267,11 @@ func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) b } } - forcedVartype := types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", varType, solver.ResolverMap{})) + if forcedVarType.Empty() { + forcedVarType = types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", varType, solver.ResolverMap{})) + } forcedParamType := types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", paramType, solver.ResolverMap{})) - - if !forcedParamType.Intersect(forcedVartype).Empty() { + if !forcedParamType.Intersect(forcedVarType).Empty() { return true } @@ -1334,7 +1341,7 @@ func (b *blockWalker) checkArrayDimFetchSafety(arg ir.Node, fn meta.FuncInfo, pa if !b.isTypeCompatible(varType, param.Typ) { b.report(arg, LevelWarning, "notSafetyCall", - "not safety array access in parameter %s of function %s", + "potential not safety array access in parameter %s of function %s", param.Name, formatSlashesFuncName(fn)) } } diff --git a/src/tests/checkers/not_safety_test.go b/src/tests/checkers/not_safety_test.go index 7ee49718..9264c264 100644 --- a/src/tests/checkers/not_safety_test.go +++ b/src/tests/checkers/not_safety_test.go @@ -408,3 +408,24 @@ class Filesystem implements FilesystemInterface } test.RunAndMatch() } + +func TestForceInferring(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`strictCallables ? self::STRICT_IS_CALLABLE : self::IS_CALLABLE; + + return sprintf($tpl, $variable, $variable); + } +} +`) + test.Expect = []string{ + "Property {\\User}->strictCallables does not exist", + } + test.RunAndMatch() +} From 184a9c12fc941753eb6762760a551fcadc88faa1 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 1 Apr 2025 05:25:49 +0300 Subject: [PATCH 25/36] refactoring --- src/linter/and_walker.go | 28 +++++++++++++-------------- src/linter/block.go | 5 +---- src/linttest/golden_linttest.go | 3 ++- src/tests/checkers/not_safety_test.go | 3 ++- src/types/predicates.go | 2 +- 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/linter/and_walker.go b/src/linter/and_walker.go index 983e0168..c521459e 100644 --- a/src/linter/and_walker.go +++ b/src/linter/and_walker.go @@ -255,13 +255,12 @@ func (a *andWalker) handleTypeCheckCondition(expectedType string, args []ir.Node continue } - // We need to traverse the variable here to check that - // it exists, since this variable will be added to the - // context later. + // Traverse the variable to ensure it exists, since this variable + // will be added to the context later a.b.handleVariable(variable) - currentType := a.exprType(variable) - + // Get the current type of the variable from the appropriate context + currentType := a.exprType(variable) // nolint:staticcheck if a.inNot { currentType = a.exprTypeInContext(a.trueContext, variable) } else { @@ -270,27 +269,28 @@ func (a *andWalker) handleTypeCheckCondition(expectedType string, args []ir.Node var trueType, falseType types.Map - if expectedType == "bool" { - // we can have false/true/bool as type that's why we should check all situation + switch expectedType { + case "bool": + // For bool: consider possible literal types "bool", "true" and "false" boolUnion := types.NewMap("bool").Union(types.NewMap("true")).Union(types.NewMap("false")) intersection := currentType.Intersect(boolUnion) if intersection.Empty() { // If there is no explicit bool subtype, then the positive branch becomes simply "bool" trueType = types.NewMap("bool") } else { - // Otherwise, we leave exactly those literals that were in the current type + // Otherwise, keep exactly those literals that were present in the current type trueType = intersection } - // Negative branch - remove all bool subtypes + // Negative branch: remove all bool subtypes falseType = currentType.Clone().Erase("bool").Erase("true").Erase("false") - } else if expectedType == "object" { - // For is_object: keys that is not primitives + case "object": + // For is_object: keep only keys that are not considered primitive keys := currentType.Keys() var objectKeys []string for _, k := range keys { switch k { case "int", "float", "string", "bool", "null", "true", "false", "mixed", "callable", "resource", "void", "iterable", "never": - // skip not object + // Skip primitive types continue default: objectKeys = append(objectKeys, k) @@ -308,8 +308,8 @@ func (a *andWalker) handleTypeCheckCondition(expectedType string, args []ir.Node for _, k := range objectKeys { falseType = falseType.Erase(k) } - } else { - // For other types, standard logic + default: + // Standard logic for other types trueType = types.NewMap(expectedType) falseType = currentType.Clone().Erase(expectedType) } diff --git a/src/linter/block.go b/src/linter/block.go index 8761c220..ef61f834 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1271,11 +1271,8 @@ func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) b forcedVarType = types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", varType, solver.ResolverMap{})) } forcedParamType := types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", paramType, solver.ResolverMap{})) - if !forcedParamType.Intersect(forcedVarType).Empty() { - return true - } - return false + return !forcedParamType.Intersect(forcedVarType).Empty() } func (b *blockWalker) checkConstFetchSafety(arg ir.Node, fn meta.FuncInfo, paramIndex int, constExpr *ir.ConstFetchExpr, haveVariadic bool) { diff --git a/src/linttest/golden_linttest.go b/src/linttest/golden_linttest.go index bfa14a13..d27ed7bf 100644 --- a/src/linttest/golden_linttest.go +++ b/src/linttest/golden_linttest.go @@ -3,7 +3,6 @@ package linttest import ( "encoding/json" "fmt" - "github.com/google/go-cmp/cmp" "log" "os" "os/exec" @@ -12,6 +11,8 @@ import ( "strings" "testing" + "github.com/google/go-cmp/cmp" + "github.com/VKCOM/noverify/src/cmd" "github.com/VKCOM/noverify/src/linter" "github.com/VKCOM/noverify/src/utils" diff --git a/src/tests/checkers/not_safety_test.go b/src/tests/checkers/not_safety_test.go index 9264c264..8ec3fdcc 100644 --- a/src/tests/checkers/not_safety_test.go +++ b/src/tests/checkers/not_safety_test.go @@ -1,8 +1,9 @@ package checkers import ( - "github.com/VKCOM/noverify/src/linttest" "testing" + + "github.com/VKCOM/noverify/src/linttest" ) func TestFunctionPassingFalse_SimpleVar(t *testing.T) { diff --git a/src/types/predicates.go b/src/types/predicates.go index 98fec14b..66b390b3 100644 --- a/src/types/predicates.go +++ b/src/types/predicates.go @@ -93,7 +93,7 @@ var scalar = map[string]bool{ "true": true, "false": true, - //"mixed": true, + // "mixed": true, } var aliases = map[string]string{ From 16b28c5857f839b233e6d9c6c4a39ab0662323d4 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 1 Apr 2025 05:33:33 +0300 Subject: [PATCH 26/36] golden tests update --- src/tests/golden/testdata/ctype/golden.txt | 39 +++++ .../golden/testdata/embeddedrules/golden.txt | 57 +++++++ .../golden/testdata/flysystem/golden.txt | 161 +++++++++++++++++- src/tests/golden/testdata/idn/golden.txt | 15 ++ src/tests/golden/testdata/math/golden.txt | 90 ++++++++++ src/tests/golden/testdata/mustache/golden.txt | 84 +++++++++ .../testdata/options-resolver/golden.txt | 45 +++++ .../golden/testdata/parsedown/golden.txt | 120 +++++++++++++ .../golden/testdata/phprocksyd/golden.txt | 78 +++++++++ src/tests/golden/testdata/qrcode/golden.txt | 72 ++++++++ .../testdata/twitter-api-php/golden.txt | 36 ++++ .../golden/testdata/underscore/golden.txt | 144 +++++++++++++++- 12 files changed, 934 insertions(+), 7 deletions(-) diff --git a/src/tests/golden/testdata/ctype/golden.txt b/src/tests/golden/testdata/ctype/golden.txt index a36379e2..aee69001 100644 --- a/src/tests/golden/testdata/ctype/golden.txt +++ b/src/tests/golden/testdata/ctype/golden.txt @@ -1,18 +1,57 @@ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:36 + return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:52 + return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:68 + return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:84 + return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text); + ^^^^^ MAYBE regexpSimplify: May re-write '/[^0-9]/' as '/\D/' at testdata/ctype/ctype.php:84 return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text); ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:100 + return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text); + ^^^^^ WARNING regexpVet: suspicious char range '!-~' in [^!-~] at testdata/ctype/ctype.php:100 return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text); ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:116 + return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:132 + return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text); + ^^^^^ WARNING regexpVet: suspicious char range ' -~' in [^ -~] at testdata/ctype/ctype.php:132 return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text); ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:148 + return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); + ^^^^^ MAYBE regexpSimplify: May re-write '/[^!-\/\:-@\[-`\{-~]/' as '/[^!-\/:-@\[-`\{-~]/' at testdata/ctype/ctype.php:148 return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); ^^^^^^^^^^^^^^^^^^^^^^^ WARNING regexpVet: suspicious char range '!-\/' in [^!-\/\:-@\[-`\{-~] at testdata/ctype/ctype.php:148 return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:164 + return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text); + ^^^^^ MAYBE regexpSimplify: May re-write '/[^\s]/' as '/\S/' at testdata/ctype/ctype.php:164 return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text); ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:180 + return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:196 + return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function is_int signature of param value at testdata/ctype/ctype.php:213 + if (!\is_int($int)) { + ^^^^ +WARNING notSafetyCall: potential not safety call in function chr signature of param codepoint at testdata/ctype/ctype.php:225 + return \chr($int); + ^^^^ diff --git a/src/tests/golden/testdata/embeddedrules/golden.txt b/src/tests/golden/testdata/embeddedrules/golden.txt index f3e3719c..2d092ada 100644 --- a/src/tests/golden/testdata/embeddedrules/golden.txt +++ b/src/tests/golden/testdata/embeddedrules/golden.txt @@ -76,9 +76,18 @@ WARNING bitwiseOps: Used & bitwise operator over bool operands, perhaps && is in WARNING bitwiseOps: Used | bitwise operator over bool operands, perhaps || is intended? at testdata/embeddedrules/bitwiseOps.php:9 $_ = (($x == 1) | ($x == 2)); // Bad 2 ^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function in_array signature of param haystack when calling function \array_keys at testdata/embeddedrules/callSimplify.php:7 + $_ = in_array('abc', array_keys($array)); // bad + ^^^^^^^^^^^^^^^^^^ MAYBE callSimplify: Could simplify to array_key_exists('abc', $array) at testdata/embeddedrules/callSimplify.php:7 $_ = in_array('abc', array_keys($array)); // bad ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function in_array signature of param haystack when calling function \array_keys at testdata/embeddedrules/callSimplify.php:9 + $_ = in_array('abc', array_keys($array), true); // don't touch, has 3rd arg + ^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function in_array signature of param haystack when calling function \array_keys at testdata/embeddedrules/callSimplify.php:10 + $_ = in_array('abc', array_keys($array), false); // don't touch, has 3rd arg + ^^^^^^^^^^^^^^^^^^ MAYBE callSimplify: Could simplify to $str[$index] at testdata/embeddedrules/callSimplify.php:14 $_ = substr($str, $index, 1); ^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,51 +118,99 @@ $_ = $b[0]{0}; WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:21 $_ = strpos($str, 10); ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strpos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:22 +$_ = strpos($str, getInt()); + ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:22 $_ = strpos($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strpos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:23 +$_ = strpos($str, getIntOrString(true)); // ok + ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:27 $_ = strrpos($str, 10); ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strrpos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:28 +$_ = strrpos($str, getInt()); + ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:28 $_ = strrpos($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strrpos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:29 +$_ = strrpos($str, getIntOrString(true)); // ok + ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:33 $_ = stripos($str, 10); ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stripos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:34 +$_ = stripos($str, getInt()); + ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:34 $_ = stripos($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stripos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:35 +$_ = stripos($str, getIntOrString(true)); // ok + ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:39 $_ = strripos($str, 10); ^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strripos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:40 +$_ = strripos($str, getInt()); + ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:40 $_ = strripos($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strripos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:41 +$_ = strripos($str, getIntOrString(true)); // ok + ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:45 $_ = strstr($str, 10); ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strstr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:46 +$_ = strstr($str, getInt()); + ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:46 $_ = strstr($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strstr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:47 +$_ = strstr($str, getIntOrString(true)); // ok + ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:51 $_ = strchr($str, 10); ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strchr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:52 +$_ = strchr($str, getInt()); + ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:52 $_ = strchr($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strchr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:53 +$_ = strchr($str, getIntOrString(true)); // ok + ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:57 $_ = strrchr($str, 10); ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strrchr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:58 +$_ = strrchr($str, getInt()); + ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:58 $_ = strrchr($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strrchr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:59 +$_ = strrchr($str, getIntOrString(true)); // ok + ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:63 $_ = stristr($str, 10); ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stristr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:64 +$_ = stristr($str, getInt()); + ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:64 $_ = stristr($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stristr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:65 +$_ = stristr($str, getIntOrString(true)); // ok + ^^^^^^^^^^^^^^^^^^^^ WARNING langDeprecated: Since PHP 7.3, the definition of case insensitive constants has been deprecated at testdata/embeddedrules/langDeprecated.php:3 define("Z_CONST", 1, true); ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/flysystem/golden.txt b/src/tests/golden/testdata/flysystem/golden.txt index 5baee732..9a4923f9 100644 --- a/src/tests/golden/testdata/flysystem/golden.txt +++ b/src/tests/golden/testdata/flysystem/golden.txt @@ -1,3 +1,6 @@ +WARNING notSafetyCall: potential not safety call in function ucfirst signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:111 + $method = 'set' . ucfirst($setting); + ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:358 if (preg_match('#^.*:$#', $item)) { ^^^^^ @@ -10,6 +13,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string2 of function strnatcmp at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:379 return strnatcmp($one['path'], $two['path']); ^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function usort signature of param callback at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:382 + usort($result, $compare); + ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function forFtpSystemType signature of param systemType at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:407 throw NotSupportedException::forFtpSystemType($systemType); ^^^^^^^^^^^ @@ -31,12 +37,24 @@ MAYBE regexpSimplify: May re-write '/^[0-9]{2,4}-[0-9]{2}-[0-9]{2}/' as '/^\d{ MAYBE callSimplify: Could simplify to $permissions[0] at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:548 return substr($permissions, 0, 1) === 'd' ? 'dir' : 'file'; ^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strtr signature of param str at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:569 + $permissions = strtr($permissions, $map); + ^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function array_sum signature of param array when calling function \str_split at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:576 + return array_sum(str_split($part)); + ^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function str_split signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:576 return array_sum(str_split($part)); ^^^^^ +WARNING notSafetyCall: potential not safety call in function array_map signature of param callback at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:580 + return octdec(implode('', array_map($mapper, $parts))); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:593 return $line !== '' && ! preg_match('#.* \.(\.)?$|^total#', $line); ^^^^^ +WARNING notSafetyCall: potential not safety call in function array_filter signature of param callback at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:596 + return array_filter($list, $filter); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function getMetadata signature of param path at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:604 return $this->getMetadata($path); ^^^^^ @@ -55,12 +73,21 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:156 $response = ftp_raw($this->connection, "OPTS UTF8 ON"); ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function substr at testdata/flysystem/src/Adapter/Ftp.php:157 + if (substr($response[0], 0, 3) !== '200') { + ^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:173 ftp_set_option($this->connection, FTP_USEPASVADDRESS, ! $this->ignorePassiveAddress); ^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:176 if ( ! ftp_pasv($this->connection, $this->passive)) { ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ftp_chdir signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:191 + if ($root && ! ftp_chdir($connection, $root)) { + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ftp_pwd signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:199 + $this->root = ftp_pwd($connection); + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:212 $this->connection, ^^^^^^^^^^^^^^^^^ @@ -70,9 +97,18 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:233 @ftp_close($this->connection); ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function fwrite signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:245 + fwrite($stream, $contents); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function fwrite signature of param data at testdata/flysystem/src/Adapter/Ftp.php:245 fwrite($stream, $contents); ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function rewind signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:246 + rewind($stream); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function fclose signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:248 + fclose($stream); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function guessMimeType signature of param path at testdata/flysystem/src/Adapter/Ftp.php:255 $result['mimetype'] = $config->get('mimetype') ?: Util::guessMimeType($path, $contents); ^^^^^ @@ -103,15 +139,27 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function listDirectoryContents signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:318 $contents = array_reverse($this->listDirectoryContents($dirname, false)); ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ftp_delete signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:322 + if ( ! ftp_delete($connection, $object['path'])) { + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter filename of function ftp_delete at testdata/flysystem/src/Adapter/Ftp.php:322 if ( ! ftp_delete($connection, $object['path'])) { ^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ftp_rmdir signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:330 + return ftp_rmdir($connection, $dirname); + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_rmdir signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:330 return ftp_rmdir($connection, $dirname); ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/flysystem/src/Adapter/Ftp.php:339 $directories = explode('/', $dirname); ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function createActualDirectory signature of param connection at testdata/flysystem/src/Adapter/Ftp.php:342 + if (false === $this->createActualDirectory($directory, $connection)) { + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ftp_chdir signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:348 + ftp_chdir($connection, $directory); + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Adapter/Ftp.php:370 if (preg_match('~^\./.*~', $item)) { ^^^^^ @@ -124,6 +172,12 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_chdir signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:391 if (@ftp_chdir($this->getConnection(), $path) === true) { ^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter subject of function preg_match at testdata/flysystem/src/Adapter/Ftp.php:403 + if (preg_match('/.* not found/', $listing[0])) { + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter subject of function preg_match at testdata/flysystem/src/Adapter/Ftp.php:407 + if (preg_match('/^total [0-9]*$/', $listing[0])) { + ^^^^^^^^^^^ MAYBE regexpSimplify: May re-write '/^total [0-9]*$/' as '/^total \d*$/' at testdata/flysystem/src/Adapter/Ftp.php:407 if (preg_match('/^total [0-9]*$/', $listing[0])) { ^^^^^^^^^^^^^^^^^^ @@ -136,18 +190,45 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_mdtm signature of param filename at testdata/flysystem/src/Adapter/Ftp.php:433 $timestamp = ftp_mdtm($this->getConnection(), $path); ^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter stream of function stream_get_contents at testdata/flysystem/src/Adapter/Ftp.php:447 + $object['contents'] = stream_get_contents($object['stream']); + ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter stream of function fclose at testdata/flysystem/src/Adapter/Ftp.php:448 + fclose($object['stream']); + ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ftp_fget signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:460 + $result = ftp_fget($this->getConnection(), $stream, $path, $this->transferMode); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_fget signature of param remote_filename at testdata/flysystem/src/Adapter/Ftp.php:460 $result = ftp_fget($this->getConnection(), $stream, $path, $this->transferMode); ^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'transferMode' at testdata/flysystem/src/Adapter/Ftp.php:460 $result = ftp_fget($this->getConnection(), $stream, $path, $this->transferMode); ^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function rewind signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:461 + rewind($stream); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function fclose signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:464 + fclose($stream); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_chmod signature of param filename at testdata/flysystem/src/Adapter/Ftp.php:479 if ( ! ftp_chmod($this->getConnection(), $mode, $path)) { ^^^^^ +WARNING notSafetyCall: potential not safety call in function listDirectoryContentsRecursive signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:496 + return $this->listDirectoryContentsRecursive($directory); + ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function normalizeListing signature of param prefix at testdata/flysystem/src/Adapter/Ftp.php:502 + return $listing ? $this->normalizeListing($listing, $directory) : []; + ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter directory of function listDirectoryContentsRecursive at testdata/flysystem/src/Adapter/Ftp.php:520 + $output = array_merge($output, $this->listDirectoryContentsRecursive($item['path'])); + ^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:544 $response = ftp_raw($this->connection, 'HELP'); ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ftp_rawlist signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:565 + return ftp_rawlist($connection, $options . ' ' . $path); + ^^^^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Ftp.php:570 $response = @ftp_raw($this->connection, trim($command)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,15 +244,33 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_chdir signature of param directory at testdata/flysystem/src/Adapter/Ftpd.php:15 if (@ftp_chdir($this->getConnection(), $path) === true) { ^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function substr at testdata/flysystem/src/Adapter/Ftpd.php:25 + if (substr($object[1], 0, 5) === "ftpd:") { + ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter item of function normalizeObject at testdata/flysystem/src/Adapter/Ftpd.php:29 + return $this->normalizeObject($object[1], ''); + ^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_rawlist signature of param directory at testdata/flysystem/src/Adapter/Ftpd.php:37 $listing = ftp_rawlist($this->getConnection(), $directory, $recursive); ^^^^^^^^^^ -WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/flysystem/src/Adapter/Ftpd.php:39 +WARNING notSafetyCall: potential not safety array access in parameter string of function substr at testdata/flysystem/src/Adapter/Ftpd.php:39 if ($listing === false || ( ! empty($listing) && substr($listing[0], 0, 5) === "ftpd:")) { ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function normalizeListing signature of param prefix at testdata/flysystem/src/Adapter/Ftpd.php:43 return $this->normalizeListing($listing, $directory); ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ensureDirectory signature of param root at testdata/flysystem/src/Adapter/Local.php:78 + $this->ensureDirectory($root); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function is_dir signature of param filename at testdata/flysystem/src/Adapter/Local.php:80 + if ( ! is_dir($root) || ! is_readable($root)) { + ^^^^^ +WARNING notSafetyCall: potential not safety call in function is_readable signature of param filename at testdata/flysystem/src/Adapter/Local.php:80 + if ( ! is_dir($root) || ! is_readable($root)) { + ^^^^^ +WARNING notSafetyCall: potential not safety call in function setPathPrefix signature of param prefix at testdata/flysystem/src/Adapter/Local.php:84 + $this->setPathPrefix($root); + ^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Local.php:103 if ( ! @mkdir($root, $this->permissionMap['dir']['public'], true)) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -199,6 +298,12 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_copy_to_stream signature of param from at testdata/flysystem/src/Adapter/Local.php:159 if ( ! $stream || stream_copy_to_stream($resource, $stream) === false || ! fclose($stream)) { ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stream_copy_to_stream signature of param to at testdata/flysystem/src/Adapter/Local.php:159 + if ( ! $stream || stream_copy_to_stream($resource, $stream) === false || ! fclose($stream)) { + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function fclose signature of param stream at testdata/flysystem/src/Adapter/Local.php:159 + if ( ! $stream || stream_copy_to_stream($resource, $stream) === false || ! fclose($stream)) { + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:179 $location = $this->applyPathPrefix($path); ^^^^^ @@ -247,6 +352,15 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Local.php:263 return @unlink($location); ^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function getFilePath signature of param file at testdata/flysystem/src/Adapter/Local.php:281 + $path = $this->getFilePath($file); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function normalizeFileInfo signature of param file at testdata/flysystem/src/Adapter/Local.php:287 + $result[] = $this->normalizeFileInfo($file); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function array_filter signature of param array at testdata/flysystem/src/Adapter/Local.php:292 + return array_filter($result); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:300 $location = $this->applyPathPrefix($path); ^^^^^ @@ -259,6 +373,9 @@ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:344 $location = $this->applyPathPrefix($path); ^^^^^ +WARNING notSafetyCall: potential not safety call in function octdec signature of param octal_string when calling function \substr at testdata/flysystem/src/Adapter/Local.php:346 + $permissions = octdec(substr(sprintf('%o', fileperms($location)), -4)); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:365 $location = $this->applyPathPrefix($path); ^^^^^ @@ -271,12 +388,30 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:403 $location = $this->applyPathPrefix($dirname); ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function guardAgainstUnreadableFileInfo signature of param file at testdata/flysystem/src/Adapter/Local.php:413 + $this->guardAgainstUnreadableFileInfo($file); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function deleteFileInfoObject signature of param file at testdata/flysystem/src/Adapter/Local.php:414 + $this->deleteFileInfoObject($file); + ^^^^^ MAYBE invalidDocblockType: Void type can only be used as a standalone type for the return type at testdata/flysystem/src/Adapter/Local.php:444 * @return array|void ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function trim signature of param string when calling function \str_replace at testdata/flysystem/src/Adapter/Local.php:471 + return trim(str_replace('\\', '/', $path), '/'); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING invalidDocblockRef: @see tag refers to unknown symbol League\Flysystem\ReadInterface::readStream at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:17 * @see League\Flysystem\ReadInterface::readStream() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function fwrite signature of param stream at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:26 + fwrite($stream, $data['contents']); + ^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter data of function fwrite at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:26 + fwrite($stream, $data['contents']); + ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function rewind signature of param stream at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:27 + rewind($stream); + ^^^^^^^ WARNING invalidDocblockRef: @see tag refers to unknown symbol League\Flysystem\ReadInterface::read at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:41 * @see League\Flysystem\ReadInterface::read() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -343,6 +478,9 @@ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or speci WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/flysystem/src/Handler.php:28 public function __construct(FilesystemInterface $filesystem = null, $path = null) ^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function mountFilesystem signature of param prefix at testdata/flysystem/src/MountManager.php:57 + $this->mountFilesystem($prefix, $filesystem); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function mountFilesystem signature of param filesystem at testdata/flysystem/src/MountManager.php:57 $this->mountFilesystem($prefix, $filesystem); ^^^^^^^^^^^ @@ -367,6 +505,12 @@ MAYBE deprecatedUntagged: Call to deprecated method {\League\Flysystem\Filesys WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/flysystem/src/MountManager.php:642 public function get($path, Handler $handler = null) ^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter dirname of function deleteDir at testdata/flysystem/src/Plugin/EmptyDir.php:28 + $this->filesystem->deleteDir($item['path']); + ^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter path of function delete at testdata/flysystem/src/Plugin/EmptyDir.php:30 + $this->filesystem->delete($item['path']); + ^^^^^^^^^^^^^ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/Plugin/ForcedCopy.php:33 } catch (FileNotFoundException $e) { ^^ @@ -379,9 +523,15 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ucfirst signature of param string at testdata/flysystem/src/Plugin/GetWithMetadata.php:42 if ( ! method_exists($this->filesystem, $method = 'get' . ucfirst($key))) { ^^^^ +WARNING notSafetyCall: potential not safety call in function array_filter signature of param callback at testdata/flysystem/src/Plugin/ListFiles.php:33 + return array_values(array_filter($contents, $filter)); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/flysystem/src/Plugin/PluggableTrait.php:72 return call_user_func_array($callback, $arguments); ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function invokePlugin signature of param filesystem at testdata/flysystem/src/Plugin/PluggableTrait.php:88 + return $this->invokePlugin($method, $arguments, $this); + ^^^^^ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/Plugin/PluggableTrait.php:89 } catch (PluginNotFoundException $e) { ^^ @@ -397,6 +547,12 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\UnreadableFileException::forFileInfo public method at testdata/flysystem/src/UnreadableFileException.php:9 public static function forFileInfo(SplFileInfo $fileInfo) ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter path of function pathinfo at testdata/flysystem/src/Util.php:27 + $pathinfo += pathinfo($pathinfo['basename']); + ^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function detectByContent signature of param content at testdata/flysystem/src/Util.php:186 + $mimeType = MimeType::detectByContent($content); + ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function pathinfo signature of param path at testdata/flysystem/src/Util.php:214 $listing[] = static::pathinfo($directory) + ['type' => 'dir']; ^^^^^^^^^^ @@ -460,3 +616,6 @@ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or speci MAYBE ternarySimplify: Could rewrite as `static::$extensionToMimeTypeMap[$extension] ?? 'text/plain'` at testdata/flysystem/src/Util/MimeType.php:222 return isset(static::$extensionToMimeTypeMap[$extension]) ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strtolower signature of param string when calling function \pathinfo at testdata/flysystem/src/Util/MimeType.php:234 + $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/idn/golden.txt b/src/tests/golden/testdata/idn/golden.txt index fb12b3d5..17a6aecb 100644 --- a/src/tests/golden/testdata/idn/golden.txt +++ b/src/tests/golden/testdata/idn/golden.txt @@ -64,6 +64,9 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/idn/idn.php:249 $output = substr($input, 0, $pos++); ^^^^^^ +WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/idn/idn.php:254 + $outputLength = \strlen($output); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/idn/idn.php:255 $inputLength = \strlen($input); ^^^^^^ @@ -73,3 +76,15 @@ MAYBE assignOp: Could rewrite as `$n += (int) ($i / $outputLength)` at testdat MAYBE assignOp: Could rewrite as `$i %= $outputLength` at testdata/idn/idn.php:275 $i = $i % $outputLength; ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function mb_substr signature of param string at testdata/idn/idn.php:276 + $output = mb_substr($output, 0, $i, 'utf-8').mb_chr($n, 'utf-8').mb_substr($output, $i, $outputLength - 1, 'utf-8'); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function mb_substr signature of param length at testdata/idn/idn.php:276 + $output = mb_substr($output, 0, $i, 'utf-8').mb_chr($n, 'utf-8').mb_substr($output, $i, $outputLength - 1, 'utf-8'); + ^^ +WARNING notSafetyCall: potential not safety call in function mb_substr signature of param string at testdata/idn/idn.php:276 + $output = mb_substr($output, 0, $i, 'utf-8').mb_chr($n, 'utf-8').mb_substr($output, $i, $outputLength - 1, 'utf-8'); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function mb_substr signature of param start at testdata/idn/idn.php:276 + $output = mb_substr($output, 0, $i, 'utf-8').mb_chr($n, 'utf-8').mb_substr($output, $i, $outputLength - 1, 'utf-8'); + ^^ diff --git a/src/tests/golden/testdata/math/golden.txt b/src/tests/golden/testdata/math/golden.txt index 98474b6a..daa248f3 100644 --- a/src/tests/golden/testdata/math/golden.txt +++ b/src/tests/golden/testdata/math/golden.txt @@ -1,33 +1,105 @@ WARNING unused: Variable $a is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/math/src/BigDecimal.php:292 [$a, $b] = $this->scaleValues($this, $that); ^^ +WARNING notSafetyCall: potential not safety call in function str_repeat signature of param times at testdata/math/src/BigDecimal.php:464 + $value .= \str_repeat('0', $addDigits); + ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param length at testdata/math/src/BigDecimal.php:472 + $value = \substr($value, 0, $addDigits); + ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function sqrt signature of param n at testdata/math/src/BigDecimal.php:475 + $value = Calculator::get()->sqrt($value); + ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function of signature of param value at testdata/math/src/BigDecimal.php:588 $that = BigNumber::of($that); ^^^^^ +WARNING notSafetyCall: potential not safety call in function str_pad signature of param string at testdata/math/src/BigDecimal.php:847 + $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT); + ^^^^^^ +WARNING notSafetyCall: potential not safety call in function str_pad signature of param length at testdata/math/src/BigDecimal.php:847 + $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT); + ^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ltrim signature of param string at testdata/math/src/BigInteger.php:105 + $number = \ltrim($number, '0'); + ^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter char of function charNotInAlphabet at testdata/math/src/BigInteger.php:163 + throw NumberFormatException::charNotInAlphabet($matches[0]); + ^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/math/src/BigInteger.php:435 new BigInteger($remainder) ^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function quotient signature of param that at testdata/math/src/BigInteger.php:649 + return $this->quotient($operand); + ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function dividedBy signature of param that at testdata/math/src/BigInteger.php:652 + return $this->dividedBy($operand, RoundingMode::UP); + ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function of signature of param value at testdata/math/src/BigInteger.php:742 $that = BigNumber::of($that); ^^^^^ +WARNING notSafetyCall: potential not safety call in function is_int signature of param value at testdata/math/src/BigNumber.php:64 + if (\is_int($value)) { + ^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/math/src/BigNumber.php:74 + if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) { + ^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter number of function cleanUp at testdata/math/src/BigNumber.php:79 + $numerator = self::cleanUp($matches['integral']); + ^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function ltrim at testdata/math/src/BigNumber.php:80 + $denominator = \ltrim($matches['denominator'], '0'); + ^^^^^^^^^^^^^^^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$matches['fractional'] ?? ''` at testdata/math/src/BigNumber.php:90 $fractional = isset($matches['fractional']) ? $matches['fractional'] : ''; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter number of function cleanUp at testdata/math/src/BigNumber.php:107 + $integral = self::cleanUp($matches['integral']); + ^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function setlocale signature of param rest at testdata/math/src/BigNumber.php:131 + \setlocale(LC_NUMERIC, $currentLocale); + ^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function of signature of param value at testdata/math/src/BigNumber.php:171 + $value = static::of($value); + ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function isLessThan signature of param that at testdata/math/src/BigNumber.php:173 if ($min === null || $value->isLessThan($min)) { ^^^^ +WARNING notSafetyCall: potential not safety call in function of signature of param value at testdata/math/src/BigNumber.php:203 + $value = static::of($value); + ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function isGreaterThan signature of param that at testdata/math/src/BigNumber.php:205 if ($max === null || $value->isGreaterThan($max)) { ^^^^ +WARNING notSafetyCall: potential not safety call in function of signature of param value at testdata/math/src/BigNumber.php:236 + $value = static::of($value); + ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function add signature of param a at testdata/math/src/BigNumber.php:241 $sum = self::add($sum, $value); ^^^^ +WARNING notSafetyCall: potential not safety call in function ltrim signature of param string at testdata/math/src/BigNumber.php:307 + $number = \ltrim($number, '0'); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function quotient signature of param that at testdata/math/src/BigRational.php:354 + $numerator = $this->numerator->quotient($gcd); + ^^^^ +WARNING notSafetyCall: potential not safety call in function quotient signature of param that at testdata/math/src/BigRational.php:355 + $denominator = $this->denominator->quotient($gcd); + ^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function minus signature of param that at testdata/math/src/BigRational.php:365 return $this->minus($that)->getSign(); ^^^^^ MAYBE implicitModifiers: Specify the access modifier for \Brick\Math\Internal\Calculator::powmod method explicitly at testdata/math/src/Internal/Calculator.php:260 abstract function powmod(string $base, string $exp, string $mod) : string; ^^^^^^ +WARNING notSafetyCall: potential not safety call in function toArbitraryBase signature of param number at testdata/math/src/Internal/Calculator.php:333 + $number = $this->toArbitraryBase($number, self::ALPHABET, $base); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function twosComplement signature of param number at testdata/math/src/Internal/Calculator.php:605 + $value = $this->twosComplement($value); + ^^^^^^ +WARNING notSafetyCall: potential not safety call in function toDecimal signature of param bytes at testdata/math/src/Internal/Calculator.php:608 + $result = $this->toDecimal($value); + ^^^^^^ MAYBE assignOp: Could rewrite as `$number ^= $xor` at testdata/math/src/Internal/Calculator.php:622 $number = $number ^ $xor; ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,9 +112,27 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/math/src/Internal/Calculator/GmpCalculator.php:67 \gmp_strval($r) ^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function neg signature of param n at testdata/math/src/Internal/Calculator/NativeCalculator.php:79 + $result = $this->neg($result); + ^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/math/src/Internal/Calculator/NativeCalculator.php:187 (string) $r ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:322 + $blockA = \substr($a, $i, $blockLength); + ^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:323 + $blockB = \substr($b, $i, $blockLength); + ^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:392 + $blockA = \substr($a, $i, $blockLength); + ^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:393 + $blockB = \substr($b, $i, $blockLength); + ^^ +WARNING notSafetyCall: potential not safety call in function doCmp signature of param a at testdata/math/src/Internal/Calculator/NativeCalculator.php:532 + $cmp = $this->doCmp($focus, $b); + ^^^^^^ ERROR classMembersOrder: Constant UNNECESSARY must go before methods in the class RoundingMode at testdata/math/src/RoundingMode.php:33 public const UNNECESSARY = 0; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/mustache/golden.txt b/src/tests/golden/testdata/mustache/golden.txt index 761638cd..cdde65e6 100644 --- a/src/tests/golden/testdata/mustache/golden.txt +++ b/src/tests/golden/testdata/mustache/golden.txt @@ -1,9 +1,15 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function realpath signature of param path at testdata/mustache/src/Mustache/Autoloader.php:39 $realDir = realpath($baseDir); ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function is_dir signature of param filename at testdata/mustache/src/Mustache/Autoloader.php:40 + if (is_dir($realDir)) { + ^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$baseDir ?: 0` at testdata/mustache/src/Mustache/Autoloader.php:56 $key = $baseDir ? $baseDir : 0; ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strpos signature of param haystack at testdata/mustache/src/Mustache/Autoloader.php:79 + if (strpos($class, 'Mustache') !== 0) { + ^^^^^^ ERROR undefinedClass: Class or interface named \Psr\Log\LoggerInterface does not exist at testdata/mustache/src/Mustache/Cache/AbstractCache.php:26 * @return Mustache_Logger|Psr\Log\LoggerInterface ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,15 +22,24 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:140 if (false !== @file_put_contents($tempFile, $value)) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function file_put_contents signature of param filename at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:140 + if (false !== @file_put_contents($tempFile, $value)) { + ^^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:141 if (@rename($tempFile, $fileName)) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function rename signature of param from at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:141 + if (@rename($tempFile, $fileName)) { + ^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$this->fileMode ?? (0666 & ~umask())` at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:142 $mode = isset($this->fileMode) ? $this->fileMode : (0666 & ~umask()); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:143 @chmod($fileName, $mode); ^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function chmod signature of param permissions at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:143 + @chmod($fileName, $mode); + ^^^^^ WARNING useEval: Don't use the 'eval' function at testdata/mustache/src/Mustache/Cache/NoopCache.php:45 eval('?>' . $value); ^^^^^^^^^^^^^^^^^^^ @@ -106,6 +121,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING unused: Variable $keystr is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/mustache/src/Mustache/Compiler.php:289 $keystr = var_export($key, true); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function var_export signature of param value when calling function \substr at testdata/mustache/src/Mustache/Compiler.php:373 + $source = var_export(substr($this->source, $start, $end - $start), true); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function getFindMethod signature of param id at testdata/mustache/src/Mustache/Compiler.php:556 $method = $this->getFindMethod($name); ^^^^^ @@ -187,12 +205,18 @@ MAYBE callSimplify: Could simplify to $this->stack[] = $value at testdata/must MAYBE callSimplify: Could simplify to $this->blockStack[] = $value at testdata/mustache/src/Mustache/Context.php:49 array_push($this->blockStack, $value); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function array_shift signature of param array at testdata/mustache/src/Mustache/Context.php:130 + $first = array_shift($chunks); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:131 $value = $this->findVariableInStack($first, $this->stack); ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:138 $value = $this->findVariableInStack($chunk, array($value)); ^^^^^^ +WARNING notSafetyCall: potential not safety call in function array_shift signature of param array at testdata/mustache/src/Mustache/Context.php:162 + $first = array_shift($chunks); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:174 $value = $this->findVariableInStack($chunk, array($value)); ^^^^^^ @@ -217,6 +241,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access MAYBE misspellComment: "entitity" is a misspelling of "entity" at testdata/mustache/src/Mustache/Engine.php:254 public function getEntityFlags() ^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function addHelper signature of param name at testdata/mustache/src/Mustache/Engine.php:373 + $this->addHelper($name, $helper); + ^^^^^ ERROR undefinedClass: Class or interface named \Psr\Log\LoggerInterface does not exist at testdata/mustache/src/Mustache/Engine.php:451 * @param Mustache_Logger|Psr\Log\LoggerInterface $logger ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -238,6 +265,15 @@ ERROR undefinedMethod: Call to undefined method {\Mustache_Cache}->setLogger() MAYBE ternarySimplify: Could rewrite as `$this->delimiters ?: '{{ }}'` at testdata/mustache/src/Mustache/Engine.php:628 'delimiters' => $this->delimiters ? $this->delimiters : '{{ }}', ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function md5 signature of param string at testdata/mustache/src/Mustache/Engine.php:645 + return $this->templateClassPrefix . md5($key); + ^^^^ +WARNING notSafetyCall: potential not safety call in function parse signature of param source at testdata/mustache/src/Mustache/Engine.php:808 + $tree = $this->parse($source); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function compile signature of param source at testdata/mustache/src/Mustache/Engine.php:813 + return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'charset' at testdata/mustache/src/Mustache/Engine.php:813 return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags); ^^^^^^^^^^^^^^ @@ -268,18 +304,42 @@ MAYBE missingPhpdoc: Missing PHPDoc for \Mustache_Exception_UnknownTemplateExc WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/mustache/src/Mustache/Exception/UnknownTemplateException.php:23 public function __construct($templateName, Exception $previous = null) ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function add signature of param name at testdata/mustache/src/Mustache/HelperCollection.php:39 + $this->add($name, $helper); + ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function addLoader signature of param loader at testdata/mustache/src/Mustache/Loader/CascadingLoader.php:35 $this->addLoader($loader); ^^^^^^^ +WARNING notSafetyCall: potential not safety accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:52 + if (strpos($this->baseDir, '://') === false) { + ^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:53 + $this->baseDir = realpath($this->baseDir); + ^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:56 + if ($this->shouldCheckPath() && !is_dir($this->baseDir)) { + ^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function ltrim at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:64 $this->extension = '.' . ltrim($options['extension'], '.'); ^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:133 + return strpos($this->baseDir, '://') === false || strpos($this->baseDir, 'file://') === 0; + ^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:133 + return strpos($this->baseDir, '://') === false || strpos($this->baseDir, 'file://') === 0; + ^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentConstFetch: null passed to non-nullable parameter context in function file_get_contents at testdata/mustache/src/Mustache/Loader/InlineLoader.php:114 $data = file_get_contents($this->fileName, false, null, $this->offset); ^^^^ +WARNING notSafetyCall: potential not safety call in function preg_split signature of param subject at testdata/mustache/src/Mustache/Loader/InlineLoader.php:115 + foreach (preg_split("/^@@(?= [\w\d\.]+$)/m", $data, -1) as $chunk) { + ^^^^^ WARNING regexpVet: '\w' intersects with '\d' in [\w\d\.] at testdata/mustache/src/Mustache/Loader/InlineLoader.php:115 foreach (preg_split("/^@@(?= [\w\d\.]+$)/m", $data, -1) as $chunk) { ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function setLevel signature of param level at testdata/mustache/src/Mustache/Logger/StreamLogger.php:46 + $this->setLevel($level); + ^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'stream' at testdata/mustache/src/Mustache/Logger/StreamLogger.php:61 fclose($this->stream); ^^^^^^^^^^^^^ @@ -295,6 +355,9 @@ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference w WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'stream' at testdata/mustache/src/Mustache/Logger/StreamLogger.php:136 fwrite($this->stream, self::formatLine($level, $message, $context)); ^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strtoupper signature of param string at testdata/mustache/src/Mustache/Logger/StreamLogger.php:150 + return strtoupper($level); + ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function enablePragma signature of param name at testdata/mustache/src/Mustache/Parser.php:58 $this->enablePragma($pragma); ^^^^^^^ @@ -328,9 +391,30 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function trim signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:110 if ($delimiters = trim($delimiters)) { ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function changeDelimiters signature of param index at testdata/mustache/src/Mustache/Tokenizer.php:145 + $i = $this->changeDelimiters($text, $i); + ^^ +WARNING notSafetyCall: potential not safety call in function addPragma signature of param index at testdata/mustache/src/Mustache/Tokenizer.php:148 + $i = $this->addPragma($text, $i); + ^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:188 if (substr($lastName, -1) === '}') { ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function trim signature of param string when calling function \substr at testdata/mustache/src/Mustache/Tokenizer.php:189 + $token[self::NAME] = trim(substr($lastName, 0, -1)); + ^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:189 $token[self::NAME] = trim(substr($lastName, 0, -1)); ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function trim signature of param string when calling function \substr at testdata/mustache/src/Mustache/Tokenizer.php:283 + $this->setDelimiters(trim(substr($text, $startIndex, $closeIndex - $startIndex))); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/mustache/src/Mustache/Tokenizer.php:283 + $this->setDelimiters(trim(substr($text, $startIndex, $closeIndex - $startIndex))); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety accessing property 'ctag' at testdata/mustache/src/Mustache/Tokenizer.php:330 + $end = strpos($text, $this->ctag, $index); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function trim signature of param string when calling function \substr at testdata/mustache/src/Mustache/Tokenizer.php:331 + $pragma = trim(substr($text, $index + 2, $end - $index - 2)); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/options-resolver/golden.txt b/src/tests/golden/testdata/options-resolver/golden.txt index 87db7f21..dc4ae991 100644 --- a/src/tests/golden/testdata/options-resolver/golden.txt +++ b/src/tests/golden/testdata/options-resolver/golden.txt @@ -31,6 +31,9 @@ MAYBE deprecated: Call to deprecated method {\ReflectionParameter}->getClass() MAYBE deprecated: Call to deprecated method {\ReflectionParameter}->getClass() (since: 8.0, reason: Use ReflectionParameter::getType() and the ReflectionType APIs should be used instead) at testdata/options-resolver/OptionsResolver.php:209 if (isset($params[0]) && null !== ($class = $params[0]->getClass()) && self::class === $class->name && (!isset($params[1]) || (null !== ($class = $params[1]->getClass()) && Options::class === $class->name))) { ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function setDefault signature of param option at testdata/options-resolver/OptionsResolver.php:251 + $this->setDefault($option, $value); + ^^^^^^^ WARNING invalidDocblock: @param for non-existing argument $package at testdata/options-resolver/OptionsResolver.php:424 * @param string $package The name of the composer package that is triggering the deprecation ^^^^^^^^ @@ -40,18 +43,60 @@ WARNING invalidDocblock: @param for non-existing argument $version at testdata/o WARNING invalidDocblock: @param for non-existing argument $message at testdata/options-resolver/OptionsResolver.php:426 * @param string|\Closure $message The deprecation message to use ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:870 + throw new UndefinedOptionsException(sprintf((\count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Defined options are: "%s".', $this->formatOptions(array_keys($diff)), implode('", "', array_keys($clone->defined)))); + ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:886 + throw new MissingOptionsException(sprintf(\count($diff) > 1 ? 'The required options "%s" are missing.' : 'The required option "%s" is missing.', $this->formatOptions(array_keys($diff)))); + ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function offsetGet signature of param option at testdata/options-resolver/OptionsResolver.php:895 + $clone->offsetGet($option); + ^^^^^^^ MAYBE complexity: Too big method: more than 150 lines at testdata/options-resolver/OptionsResolver.php:917 public function offsetGet($option, bool $triggerDeprecation = true) ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:947 + throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:974 + throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1000 + if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { + ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1000 if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { ^^^^^^ +WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1000 + if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { + ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1000 if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { ^^^^^^ +WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:1076 + throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter package of function trigger_deprecation at testdata/options-resolver/OptionsResolver.php:1090 + trigger_deprecation($deprecation['package'], $deprecation['version'], strtr($message, ['%name%' => $option])); + ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter version of function trigger_deprecation at testdata/options-resolver/OptionsResolver.php:1090 + trigger_deprecation($deprecation['package'], $deprecation['version'], strtr($message, ['%name%' => $option])); + ^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strtr signature of param str at testdata/options-resolver/OptionsResolver.php:1090 + trigger_deprecation($deprecation['package'], $deprecation['version'], strtr($message, ['%name%' => $option])); + ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:1099 + throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); + ^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $invalidTypes in PHPDoc, 'array' type hint too generic at testdata/options-resolver/OptionsResolver.php:1123 private function verifyTypes(string $type, $value, array &$invalidTypes, int $level = 0): bool ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1130 + if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { + ^^^^^ +WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1130 + if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { + ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function get_class signature of param object at testdata/options-resolver/OptionsResolver.php:1221 return \get_class($value); ^^^^^^ diff --git a/src/tests/golden/testdata/parsedown/golden.txt b/src/tests/golden/testdata/parsedown/golden.txt index 0287d630..7063620b 100644 --- a/src/tests/golden/testdata/parsedown/golden.txt +++ b/src/tests/golden/testdata/parsedown/golden.txt @@ -1,6 +1,12 @@ MAYBE implicitModifiers: Specify the access modifier for \Parsedown::text method explicitly at testdata/parsedown/parsedown.php:24 function text($text) ^^^^ +WARNING notSafetyCall: potential not safety call in function trim signature of param string at testdata/parsedown/parsedown.php:46 + $text = trim($text, "\n"); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function linesElements signature of param lines at testdata/parsedown/parsedown.php:52 + return $this->linesElements($lines); + ^^^^^^ MAYBE implicitModifiers: Specify the access modifier for \Parsedown::setBreaksEnabled method explicitly at testdata/parsedown/parsedown.php:59 function setBreaksEnabled($breaksEnabled) ^^^^^^^^^^^^^^^^ @@ -28,9 +34,18 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strstr signature of param haystack at testdata/parsedown/parsedown.php:186 while (($beforeTab = strstr($line, "\t", true)) !== false) ^^^^^ +WARNING notSafetyCall: potential not safety call in function mb_strlen signature of param string at testdata/parsedown/parsedown.php:188 + $shortage = 4 - mb_strlen($beforeTab, 'utf-8') % 4; + ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function str_repeat signature of param times at testdata/parsedown/parsedown.php:191 + . str_repeat(' ', $shortage) + ^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:192 . substr($line, strlen($beforeTab) + 1) ^^^^^ +WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:192 + . substr($line, strlen($beforeTab) + 1) + ^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strspn signature of param string at testdata/parsedown/parsedown.php:196 $indent = strspn($line, ' '); ^^^^^ @@ -67,6 +82,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strspn signature of param characters at testdata/parsedown/parsedown.php:452 $openerLength = strspn($Line['text'], $marker); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function trim signature of param string when calling function \substr at testdata/parsedown/parsedown.php:459 + $infostring = trim(substr($Line['text'], $openerLength), "\t "); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:459 $infostring = trim(substr($Line['text'], $openerLength), "\t "); ^^^^^^^^^^^^^ @@ -85,6 +103,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter characters of function strspn at testdata/parsedown/parsedown.php:516 if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength'] ^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function chop signature of param string when calling function \substr at testdata/parsedown/parsedown.php:517 + and chop(substr($Line['text'], $len), ' ') === '' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:517 and chop(substr($Line['text'], $len), ' ') === '' ^^^^^^^^^^^^^ @@ -103,6 +124,24 @@ MAYBE typeHint: Specify the type for the parameter $CurrentBlock in PHPDoc, 'a WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:578 if (preg_match('/^('.$pattern.'([ ]++|$))(.*+)/', $Line['text'], $matches)) ^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:580 + $contentIndent = strlen($matches[2]); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function substr at testdata/parsedown/parsedown.php:585 + $matches[1] = substr($matches[1], 0, -$contentIndent); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter haystack of function strstr at testdata/parsedown/parsedown.php:593 + $markerWithoutWhitespace = strstr($matches[1], ' ', true); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/parsedown/parsedown.php:601 + 'markerType' => ($name === 'ul' ? $markerWithoutWhitespace : substr($markerWithoutWhitespace, -1)), + ^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ltrim signature of param string when calling function \strstr at testdata/parsedown/parsedown.php:612 + $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter haystack of function strstr at testdata/parsedown/parsedown.php:612 + $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; + ^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:633 'destination' => 'elements' ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,6 +169,9 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:712 $text = substr($Line['body'], $requiredIndent); ^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/parsedown/parsedown.php:712 + $text = substr($Line['body'], $requiredIndent); + ^^^^^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:729 protected function blockListComplete(array $Block) ^^^^^^^^^^^^^^^^^ @@ -169,6 +211,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:836 if (preg_match('/^<[\/]?+(\w*)(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+(\/)?>/', $Line['text'], $matches)) ^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strtolower at testdata/parsedown/parsedown.php:838 + $element = strtolower($matches[1]); + ^^^^^^^^^^^ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings at testdata/parsedown/parsedown.php:840 if (in_array($element, $this->textLevelElements)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,6 +229,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access MAYBE regexpSimplify: May re-write '/^\[(.+?)\]:[ ]*+?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/' as '/^\[(.+?)\]: *+?(?: +["'(](.+)["')])? *+$/' at testdata/parsedown/parsedown.php:875 and preg_match('/^\[(.+?)\]:[ ]*+?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/', $Line['text'], $matches) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strtolower at testdata/parsedown/parsedown.php:877 + $id = strtolower($matches[1]); + ^^^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$matches[3] ?? null` at testdata/parsedown/parsedown.php:881 'title' => isset($matches[3]) ? $matches[3] : null, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -226,6 +274,27 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1093 protected function paragraphContinue($Line, array $Block) ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strpbrk signature of param string at testdata/parsedown/parsedown.php:1149 + while ($excerpt = strpbrk($text, $this->inlineMarkerList)) + ^^^^^ +WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1153 + $markerPosition = strlen($text) - strlen($excerpt); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1153 + $markerPosition = strlen($text) - strlen($excerpt); + ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1196 + $unmarkedText = substr($text, 0, $Inline['position']); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1206 + $text = substr($text, $Inline['position'] + $Inline['extent']); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1213 + $unmarkedText = substr($text, 0, $markerPosition + 1); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1218 + $text = substr($text, $markerPosition + 1); + ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1242 'extent' => strlen($text), ^^^^^ @@ -235,18 +304,27 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access MAYBE regexpSimplify: May re-write '/[ ]*+\n/' as '/ *+\n/' at testdata/parsedown/parsedown.php:1265 $text = preg_replace('/[ ]*+\n/', ' ', $text); ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1268 + 'extent' => strlen($matches[0]), + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:1284 if (strpos($Excerpt['text'], '>') !== false ^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1285 and preg_match("/^<((mailto:)?$commonMarkEmail)>/i", $Excerpt['text'], $matches) ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1295 + 'extent' => strlen($matches[0]), + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1316 if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1320 elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1330 + 'extent' => strlen($matches[0]), + ^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:1333 'handler' => array( ^ @@ -256,6 +334,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1408 if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1412 + $extent += strlen($matches[0]); + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1414 $remainder = substr($remainder, $extent); ^^^^^^^^^^ @@ -265,12 +346,24 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE regexpSimplify: May re-write '/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/' as '/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?: +("[^"]*+"|'[^']*+'))?\s*+[)]/' at testdata/parsedown/parsedown.php:1421 if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function substr at testdata/parsedown/parsedown.php:1427 + $Element['attributes']['title'] = substr($matches[2], 1, - 1); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1430 + $extent += strlen($matches[0]); + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1434 if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1436 + $definition = strlen($matches[1]) ? $matches[1] : $Element['handler']['argument']; + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strtolower signature of param string at testdata/parsedown/parsedown.php:1437 $definition = strtolower($definition); ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1439 + $extent += strlen($matches[0]); + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:1465 if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) ^^^^^^^^^^^^^^^^ @@ -280,12 +373,21 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access MAYBE regexpSimplify: May re-write '/^<\/\w[\w-]*+[ ]*+>/s' as '/^<\/\w[\w-]*+ *+>/s' at testdata/parsedown/parsedown.php:1470 if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1474 + 'extent' => strlen($matches[0]), + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1478 if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1482 + 'extent' => strlen($matches[0]), + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1486 if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1490 + 'extent' => strlen($matches[0]), + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:1497 if (substr($Excerpt['text'], 1, 1) !== ' ' and strpos($Excerpt['text'], ';') !== false ^^^^^^^^^^^^^^^^ @@ -298,9 +400,15 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1498 and preg_match('/^&(#?+[0-9a-zA-Z]++);/', $Excerpt['text'], $matches) ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1502 + 'extent' => strlen($matches[0]), + ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1516 if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1519 + 'extent' => strlen($matches[0]), + ^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:1522 'handler' => array( ^ @@ -319,6 +427,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1562 if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w++:\/{2}[^ >]++)>/i', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1567 + 'extent' => strlen($matches[0]), + ^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Element in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1591 protected function handle(array $Element) ^^^^^^ @@ -373,6 +484,9 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1832 $before = substr($text, 0, $offset); ^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param length at testdata/parsedown/parsedown.php:1832 + $before = substr($text, 0, $offset); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1833 $after = substr($text, $offset + strlen($matches[0][0])); ^^^^^ @@ -382,6 +496,9 @@ MAYBE implicitModifiers: Specify the access modifier for \Parsedown::parse met MAYBE typeHint: Specify the type for the parameter $Element in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1861 protected function sanitiseElement(array $Element) ^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1885 + if ( ! preg_match($goodAttribute, $att)) + ^^^^ WARNING unused: Variable $val is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/parsedown/parsedown.php:1882 foreach ($Element['attributes'] as $att => $val) ^^^^ @@ -397,6 +514,9 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1928 if ($len > strlen($string)) ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strtolower signature of param string when calling function \substr at testdata/parsedown/parsedown.php:1934 + return strtolower(substr($string, 0, $len)) === strtolower($needle); + ^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1934 return strtolower(substr($string, 0, $len)) === strtolower($needle); ^^^^^^^ diff --git a/src/tests/golden/testdata/phprocksyd/golden.txt b/src/tests/golden/testdata/phprocksyd/golden.txt index 9439964c..30b55e5b 100644 --- a/src/tests/golden/testdata/phprocksyd/golden.txt +++ b/src/tests/golden/testdata/phprocksyd/golden.txt @@ -31,15 +31,36 @@ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phpro WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_socket_accept signature of param socket at testdata/phprocksyd/Phprocksyd.php:200 $client = stream_socket_accept($server, self::ACCEPT_TIMEOUT, $peername); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_read_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:207 + stream_set_read_buffer($client, 0); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_write_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:208 + stream_set_write_buffer($client, 0); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_blocking signature of param stream at testdata/phprocksyd/Phprocksyd.php:209 + stream_set_blocking($client, 0); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_timeout signature of param stream at testdata/phprocksyd/Phprocksyd.php:210 + stream_set_timeout($client, self::CONN_TIMEOUT); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function pcntl_wait signature of param status at testdata/phprocksyd/Phprocksyd.php:231 $pid = pcntl_wait($status, WNOHANG); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function pcntl_wexitstatus signature of param status at testdata/phprocksyd/Phprocksyd.php:241 $Res->retcode = pcntl_wexitstatus($status); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function array_pop signature of param array at testdata/phprocksyd/Phprocksyd.php:269 + $this->read_buf[$stream_id] = array_pop($requests); + ^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rtrim signature of param string at testdata/phprocksyd/Phprocksyd.php:272 $req = rtrim($req); ^^^^ +WARNING notSafetyCall: potential not safety call in function fwrite signature of param data when calling function \substr at testdata/phprocksyd/Phprocksyd.php:295 + $wrote = fwrite($this->streams[$stream_id], substr($this->write_buf[$stream_id], 0, 65536)); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/phprocksyd/Phprocksyd.php:309 + $this->write_buf[$stream_id] = substr($this->write_buf[$stream_id], $wrote); + ^^^^^^ ERROR constCase: Constant 'NULL' should be used in lower case as 'null' at testdata/phprocksyd/Phprocksyd.php:321 $n = stream_select($read, $write, $except, NULL); ^^^^ @@ -79,6 +100,9 @@ WARNING invalidDocblock: Malformed @param $stream_id tag (maybe type is missing? WARNING invalidDocblock: Malformed @param $req tag (maybe type is missing?) at testdata/phprocksyd/Phprocksyd.php:422 * @param $req ^^^^ +WARNING notSafetyCall: potential not safety call in function posix_kill signature of param process_id at testdata/phprocksyd/Phprocksyd.php:438 + $result = posix_kill($pid, SIGTERM); + ^^^^ WARNING invalidDocblock: Malformed @param $stream_id tag (maybe type is missing?) at testdata/phprocksyd/Phprocksyd.php:443 * @param $stream_id ^^^^^^^^^^ @@ -88,6 +112,15 @@ WARNING invalidDocblock: Malformed @param $req tag (maybe type is missing?) at t WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:481 exit(0); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function explode signature of param string when calling function \microtime at testdata/phprocksyd/Phprocksyd.php:473 + $seed = floor(explode(" ", microtime())[0] * 1e6); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function srand signature of param seed at testdata/phprocksyd/Phprocksyd.php:474 + srand($seed); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function mt_srand signature of param seed at testdata/phprocksyd/Phprocksyd.php:475 + mt_srand($seed); + ^^^^^ ERROR undefinedMethod: Call to undefined method {mixed}->run() at testdata/phprocksyd/Phprocksyd.php:479 $instance->run($req['params']); ^^^ @@ -97,12 +130,36 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:557 exit(1); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_read_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:560 + stream_set_read_buffer($fp, 0); + ^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_write_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:561 + stream_set_write_buffer($fp, 0); + ^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_blocking signature of param stream at testdata/phprocksyd/Phprocksyd.php:562 + stream_set_blocking($fp, 0); + ^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_timeout signature of param stream at testdata/phprocksyd/Phprocksyd.php:563 + stream_set_timeout($fp, self::CONN_TIMEOUT); + ^^^ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:590 exit(0); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function readdir signature of param dir_handle at testdata/phprocksyd/Phprocksyd.php:598 + while (false !== ($file = readdir($dh))) { + ^^^ +WARNING notSafetyCall: potential not safety call in function fclose signature of param stream when calling function \fopen at testdata/phprocksyd/Phprocksyd.php:605 + fclose(fopen("php://fd/" . $fd, 'r+')); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:619 exit(1); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function unserialize signature of param data at testdata/phprocksyd/Phprocksyd.php:638 + $res = unserialize($contents); + ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function explode signature of param string at testdata/phprocksyd/Phprocksyd.php:667 + $parts = explode(' ', $contents); + ^^^^^^^^^ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:685 exit(0); ^^^^^^^ @@ -112,9 +169,30 @@ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Simpl WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_socket_accept signature of param socket at testdata/phprocksyd/Simple.php:65 $client = stream_socket_accept($server, 1, $peername); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_read_buffer signature of param stream at testdata/phprocksyd/Simple.php:72 + stream_set_read_buffer($client, 0); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_write_buffer signature of param stream at testdata/phprocksyd/Simple.php:73 + stream_set_write_buffer($client, 0); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_blocking signature of param stream at testdata/phprocksyd/Simple.php:74 + stream_set_blocking($client, 0); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function stream_set_timeout signature of param stream at testdata/phprocksyd/Simple.php:75 + stream_set_timeout($client, 1); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function array_pop signature of param array at testdata/phprocksyd/Simple.php:113 + $this->read_buf[$stream_id] = array_pop($requests); + ^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rtrim signature of param string at testdata/phprocksyd/Simple.php:116 $res = json_decode(rtrim($req), true); ^^^^ +WARNING notSafetyCall: potential not safety call in function fwrite signature of param data when calling function \substr at testdata/phprocksyd/Simple.php:132 + $wrote = fwrite($this->streams[$stream_id], substr($this->write_buf[$stream_id], 0, 65536)); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/phprocksyd/Simple.php:146 + $this->write_buf[$stream_id] = substr($this->write_buf[$stream_id], $wrote); + ^^^^^^ ERROR constCase: Constant 'NULL' should be used in lower case as 'null' at testdata/phprocksyd/Simple.php:158 $n = stream_select($read, $write, $except, NULL); ^^^^ diff --git a/src/tests/golden/testdata/qrcode/golden.txt b/src/tests/golden/testdata/qrcode/golden.txt index 3fb44dc4..4dcd83be 100644 --- a/src/tests/golden/testdata/qrcode/golden.txt +++ b/src/tests/golden/testdata/qrcode/golden.txt @@ -10,27 +10,60 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function imagecreatetruecolor signature of param height at testdata/qrcode/qrcode.php:56 $image = imagecreatetruecolor($width, $height); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function imagesavealpha signature of param image at testdata/qrcode/qrcode.php:57 + imagesavealpha($image, true); + ^^^^^^ MAYBE ternarySimplify: Could rewrite as `$this->options['bc'] ?? 'FFFFFF'` at testdata/qrcode/qrcode.php:59 $bgcolor = (isset($this->options['bc']) ? $this->options['bc'] : 'FFFFFF'); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function imagefill signature of param image at testdata/qrcode/qrcode.php:61 + imagefill($image, 0, 0, $bgcolor); + ^^^^^^ MAYBE ternarySimplify: Could rewrite as `$this->options['fc'] ?? '000000'` at testdata/qrcode/qrcode.php:63 $fgcolor = (isset($this->options['fc']) ? $this->options['fc'] : '000000'); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function floor signature of param num at testdata/qrcode/qrcode.php:72 $scale = (($scale > 1) ? floor($scale) : 1); ^^^^^^ +WARNING notSafetyCall: potential not safety call in function imagefilledrectangle signature of param image at testdata/qrcode/qrcode.php:93 + imagefilledrectangle($image, $rx, $ry, $rx + $rw - 1, $ry + $rh - 1, $mc); + ^^^^^^ +WARNING notSafetyCall: potential not safety call in function imagefilledrectangle signature of param x1 at testdata/qrcode/qrcode.php:93 + imagefilledrectangle($image, $rx, $ry, $rx + $rw - 1, $ry + $rh - 1, $mc); + ^^^ +WARNING notSafetyCall: potential not safety call in function imagefilledrectangle signature of param y1 at testdata/qrcode/qrcode.php:93 + imagefilledrectangle($image, $rx, $ry, $rx + $rw - 1, $ry + $rh - 1, $mc); + ^^^ +WARNING notSafetyCall: potential not safety call in function hexdec signature of param hex_string when calling function \substr at testdata/qrcode/qrcode.php:134 + $r = hexdec(substr($color, 0, 2)); + ^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:134 $r = hexdec(substr($color, 0, 2)); ^^^^^^ +WARNING notSafetyCall: potential not safety call in function hexdec signature of param hex_string when calling function \substr at testdata/qrcode/qrcode.php:135 + $g = hexdec(substr($color, 2, 2)); + ^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:135 $g = hexdec(substr($color, 2, 2)); ^^^^^^ +WARNING notSafetyCall: potential not safety call in function hexdec signature of param hex_string when calling function \substr at testdata/qrcode/qrcode.php:136 + $b = hexdec(substr($color, 4, 2)); + ^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:136 $b = hexdec(substr($color, 4, 2)); ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function imagecolorallocate signature of param image at testdata/qrcode/qrcode.php:137 return imagecolorallocate($image, $r, $g, $b); ^^^^^^ +WARNING notSafetyCall: potential not safety call in function imagecolorallocate signature of param red at testdata/qrcode/qrcode.php:137 + return imagecolorallocate($image, $r, $g, $b); + ^^ +WARNING notSafetyCall: potential not safety call in function imagecolorallocate signature of param green at testdata/qrcode/qrcode.php:137 + return imagecolorallocate($image, $r, $g, $b); + ^^ +WARNING notSafetyCall: potential not safety call in function imagecolorallocate signature of param blue at testdata/qrcode/qrcode.php:137 + return imagecolorallocate($image, $r, $g, $b); + ^^ WARNING notNullSafetyFunctionArgumentFunctionCall: not null safety call in function strtolower signature of param string when calling function \preg_replace at testdata/qrcode/qrcode.php:143 switch (strtolower(preg_replace('/[^A-Za-z0-9]/', '', $options['s']))) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,6 +112,9 @@ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condit WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:316 $group = substr($data, $i, 3); ^^^^^ +WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:317 + switch (strlen($group)) { + ^^^^^^ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testdata/qrcode/qrcode.php:318 case 3: ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,12 +139,30 @@ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condit WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:359 $group = substr($data, $i, 2); ^^^^^ +WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:360 + if (strlen($group) > 1) { + ^^^^^^ +WARNING notSafetyCall: potential not safety call in function strpos signature of param needle when calling function \substr at testdata/qrcode/qrcode.php:361 + $c1 = strpos($alphabet, substr($group, 0, 1)); + ^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/qrcode/qrcode.php:361 + $c1 = strpos($alphabet, substr($group, 0, 1)); + ^^^^^^ MAYBE callSimplify: Could simplify to $group[0] at testdata/qrcode/qrcode.php:361 $c1 = strpos($alphabet, substr($group, 0, 1)); ^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strpos signature of param needle when calling function \substr at testdata/qrcode/qrcode.php:362 + $c2 = strpos($alphabet, substr($group, 1, 1)); + ^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/qrcode/qrcode.php:362 + $c2 = strpos($alphabet, substr($group, 1, 1)); + ^^^^^^ MAYBE callSimplify: Could simplify to $group[1] at testdata/qrcode/qrcode.php:362 $c2 = strpos($alphabet, substr($group, 1, 1)); ^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function strpos signature of param needle at testdata/qrcode/qrcode.php:376 + $ch = strpos($alphabet, $group); + ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:390 $length = strlen($data); ^^^^^ @@ -118,6 +172,9 @@ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testd WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/qrcode/qrcode.php:391 switch ($version_group) { ^ +WARNING notSafetyCall: potential not safety call in function ord signature of param character when calling function \substr at testdata/qrcode/qrcode.php:413 + $ch = ord(substr($data, $i, 1)); + ^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:413 $ch = ord(substr($data, $i, 1)); ^^^^^ @@ -139,12 +196,27 @@ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condit WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:447 $group = substr($data, $i, 2); ^^^^^ +WARNING notSafetyCall: potential not safety call in function ord signature of param character when calling function \substr at testdata/qrcode/qrcode.php:448 + $c1 = ord(substr($group, 0, 1)); + ^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/qrcode/qrcode.php:448 + $c1 = ord(substr($group, 0, 1)); + ^^^^^^ MAYBE callSimplify: Could simplify to $group[0] at testdata/qrcode/qrcode.php:448 $c1 = ord(substr($group, 0, 1)); ^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function ord signature of param character when calling function \substr at testdata/qrcode/qrcode.php:449 + $c2 = ord(substr($group, 1, 1)); + ^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/qrcode/qrcode.php:449 + $c2 = ord(substr($group, 1, 1)); + ^^^^^^ MAYBE callSimplify: Could simplify to $group[1] at testdata/qrcode/qrcode.php:449 $c2 = ord(substr($group, 1, 1)); ^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function array_slice signature of param offset at testdata/qrcode/qrcode.php:520 + $blocks[] = array_slice($data, $offset, $length); + ^^^^^^^ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/qrcode/qrcode.php:697 switch ($mask) { ^ diff --git a/src/tests/golden/testdata/twitter-api-php/golden.txt b/src/tests/golden/testdata/twitter-api-php/golden.txt index 37b41176..78e73125 100644 --- a/src/tests/golden/testdata/twitter-api-php/golden.txt +++ b/src/tests/golden/testdata/twitter-api-php/golden.txt @@ -19,15 +19,51 @@ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/twitter-api-php/TwitterAPIExchange.php:223 'oauth_version' => '1.0' ^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function urldecode at testdata/twitter-api-php/TwitterAPIExchange.php:239 + $oauth[$split[0]] = urldecode($split[1]); + ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function base64_encode signature of param string when calling function \hash_hmac at testdata/twitter-api-php/TwitterAPIExchange.php:254 + $oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true)); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE invalidDocblockType: Use bool type instead of boolean at testdata/twitter-api-php/TwitterAPIExchange.php:267 * @param boolean $return If true, returns data. This is left in for backward compatibility reasons ^^^^^^^ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings at testdata/twitter-api-php/TwitterAPIExchange.php:286 if (in_array(strtolower($this->requestMethod), array('put', 'delete'))) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function curl_setopt_array signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:312 + curl_setopt_array($feed, $options); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function curl_setopt_array signature of param options at testdata/twitter-api-php/TwitterAPIExchange.php:312 + curl_setopt_array($feed, $options); + ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function curl_exec signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:313 + $json = curl_exec($feed); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function curl_getinfo signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:315 + $this->httpStatusCode = curl_getinfo($feed, CURLINFO_HTTP_CODE); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function curl_error signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:317 + if (($error = curl_error($feed)) !== '') + ^^^^^ +WARNING notSafetyCall: potential not safety call in function curl_error signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:317 + if (($error = curl_error($feed)) !== '') + ^^^^^ +WARNING notSafetyCall: potential not safety call in function curl_close signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:319 + curl_close($feed); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function curl_close signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:324 + curl_close($feed); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:345 + $return[] = rawurlencode($key) . '=' . rawurlencode($value); + ^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:345 $return[] = rawurlencode($key) . '=' . rawurlencode($value); ^^^^^^ +WARNING notSafetyCall: potential not safety call in function in_array signature of param needle at testdata/twitter-api-php/TwitterAPIExchange.php:365 + if (in_array($key, array('oauth_consumer_key', 'oauth_nonce', 'oauth_signature', + ^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/twitter-api-php/TwitterAPIExchange.php:366 'oauth_signature_method', 'oauth_timestamp', 'oauth_token', 'oauth_version'))) { ^^^^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/underscore/golden.txt b/src/tests/golden/testdata/underscore/golden.txt index 9aaf1ba1..3ab9c919 100644 --- a/src/tests/golden/testdata/underscore/golden.txt +++ b/src/tests/golden/testdata/underscore/golden.txt @@ -19,6 +19,27 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:113 $return = array(); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function first signature of param collection at testdata/underscore/underscore.php:139 + list($collection, $function_name) = $__->first($args, 2); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function map signature of param collection at testdata/underscore/underscore.php:161 + if(!is_null($iterator)) $collection = $__->map($collection, $iterator); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:162 + if(count($collection) === 0) return self::_wrap(false); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function is_int signature of param value when calling function \array_search at testdata/underscore/underscore.php:164 + return self::_wrap(is_int(array_search(true, $collection, false))); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function array_search signature of param haystack at testdata/underscore/underscore.php:164 + return self::_wrap(is_int(array_search(true, $collection, false))); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function map signature of param collection at testdata/underscore/underscore.php:177 + if(!is_null($iterator)) $collection = $__->map($collection, $iterator); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function is_bool signature of param value when calling function \array_search at testdata/underscore/underscore.php:181 + return self::_wrap(is_bool(array_search(false, $collection, false))); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:193 $return = array(); ^^^^^^^ @@ -34,27 +55,69 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/underscore/underscore.php:224 if(call_user_func($iterator, $val)) return $val; ^^^^^^^^^ +WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:226 + return self::_wrap(false); + ^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:248 if($n === 0) return self::_wrap(array()); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_splice signature of param offset at testdata/underscore/underscore.php:262 return self::_wrap(array_splice($collection, $index)); ^^^^^^ +WARNING notSafetyCall: potential not safety call in function first signature of param n at testdata/underscore/underscore.php:275 + return self::_wrap($__->first($collection, $first_index)); + ^^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:284 if($n === 0) $result = array(); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function rest signature of param collection at testdata/underscore/underscore.php:288 + $result = $__->rest($collection, -$n); + ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function select signature of param collection at testdata/underscore/underscore.php:302 + return self::_wrap($__->select($collection, function($val) { + ^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:314 $return = array(); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function flatten signature of param collection at testdata/underscore/underscore.php:319 + $return = array_merge($return, ($shallow) ? $item : $__->flatten($item)); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function rest signature of param collection at testdata/underscore/underscore.php:339 + $removes = $__->rest($args); + ^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:360 $return = array(); ^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:363 $calculated = array(); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function is_bool signature of param value when calling function \array_search at testdata/underscore/underscore.php:366 + if(is_bool(array_search($val, $calculated, true))) { + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING unused: Variable $is_sorted is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/underscore/underscore.php:356 list($collection, $is_sorted, $iterator) = self::_wrapArgs(func_get_args(), 3); ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function first signature of param collection at testdata/underscore/underscore.php:383 + $return = $__->first($arrays); + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function rest signature of param collection at testdata/underscore/underscore.php:384 + foreach($__->rest($arrays) as $next) { + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function isArray signature of param item at testdata/underscore/underscore.php:385 + if(!$__->isArray($next)) $next = str_split((string) $next); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function isArray signature of param item at testdata/underscore/underscore.php:385 + if(!$__->isArray($next)) $next = str_split((string) $next); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function array_intersect signature of param arrays at testdata/underscore/underscore.php:387 + $return = array_intersect($return, $next); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function is_bool signature of param value at testdata/underscore/underscore.php:420 + return self::_wrap((is_bool($key)) ? -1 : $key); + ^^^^ +WARNING notSafetyCall: potential not safety call in function reject signature of param collection at testdata/underscore/underscore.php:441 + $args = $__->reject($args, function($val) { + ^^^^^ MAYBE arrayAccess: Array access to non-array type \__|mixed at testdata/underscore/underscore.php:448 list($start, $stop, $step) = array(0, $args[0], 1); ^^^^^ @@ -91,6 +154,12 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function range signature of param step at testdata/underscore/underscore.php:458 $results = range($start, $stop, $step); ^^^^^ +WARNING notSafetyCall: potential not safety call in function map signature of param collection at testdata/underscore/underscore.php:475 + $num_return_arrays = $__->max($__->map($arrays, function($array) { + ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function range signature of param stop at testdata/underscore/underscore.php:478 + $return_arrays = $__->range($num_return_arrays); + ^^^^^^^^^^^^^^^^^^ MAYBE arrayAccess: Array access to non-array type \__|mixed at testdata/underscore/underscore.php:480 if(!is_array($return_arrays[$k])) $return_arrays[$k] = array(); ^^^^^^^^^^^^^^ @@ -115,9 +184,15 @@ WARNING unused: Variable $v is unused (use $_ to ignore this inspection or speci MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:497 $results = array(); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function first signature of param collection when calling function \array_keys at testdata/underscore/underscore.php:503 + $first_key = $__->first(array_keys($results)); + ^^^^^^^^^^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:514 $results = array(); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function first signature of param collection when calling function \array_keys at testdata/underscore/underscore.php:520 + $first_key = $__->first(array_keys($results)); + ^^^^^^^^^^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:529 $results = array(); ^^^^^^^ @@ -133,30 +208,66 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:549 if(!array_key_exists($key, $result)) $result[$key] = array(); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function array_slice signature of param offset at testdata/underscore/underscore.php:567 + $midpoint_values = array_slice($collection, $midpoint, 1); + ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function array_slice signature of param length at testdata/underscore/underscore.php:571 + $collection = ($calculated_value < $midpoint_calculated_value) ? array_slice($collection, 0, $midpoint, true) : array_slice($collection, $midpoint, null, true); + ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function array_slice signature of param offset at testdata/underscore/underscore.php:571 + $collection = ($calculated_value < $midpoint_calculated_value) ? array_slice($collection, 0, $midpoint, true) : array_slice($collection, $midpoint, null, true); + ^^^^^^^^^ WARNING unused: Variable $__ is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/underscore/underscore.php:561 $__ = new self; ^^^ WARNING unused: Variable $args is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/underscore/underscore.php:615 $args = self::_wrapArgs(func_get_args(), 1); ^^^^^ +WARNING notSafetyCall: potential not safety call in function rest signature of param collection at testdata/underscore/underscore.php:643 + $extensions = $__->rest($args); + ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function get_class signature of param object at testdata/underscore/underscore.php:658 return self::_wrap(get_class_methods(get_class($object))); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_key_exists signature of param key at testdata/underscore/underscore.php:703 return self::_wrap(array_key_exists($key, $collection)); ^^^^ -ERROR undefinedProperty: Property {\__|mixed|null}->isEqual does not exist at testdata/underscore/underscore.php:723 +WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:713 + if($a === $b) return self::_wrap(true); + ^^^^ +WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:714 + if(gettype($a) !== gettype($b)) return self::_wrap(false); + ^^^^^ +WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:715 + if(is_callable($a) !== is_callable($b)) return self::_wrap(false); + ^^^^^ +WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:717 + if($a == $b) return self::_wrap(true); + ^^^^ +ERROR undefinedProperty: Property {array}->isEqual does not exist at testdata/underscore/underscore.php:723 if(is_object($a) && isset($a->isEqual)) return self::_wrap($a->isEqual($b)); ^^^^^^^ -ERROR undefinedProperty: Property {mixed|null}->isEqual does not exist at testdata/underscore/underscore.php:724 +ERROR undefinedMethod: Call to undefined method {array}->isEqual() at testdata/underscore/underscore.php:723 + if(is_object($a) && isset($a->isEqual)) return self::_wrap($a->isEqual($b)); + ^^^^^^^ +ERROR undefinedProperty: Property {object}->isEqual does not exist at testdata/underscore/underscore.php:724 if(is_object($b) && isset($b->isEqual)) return self::_wrap($b->isEqual($a)); ^^^^^^^ -ERROR undefinedMethod: Call to undefined method {mixed|null}->isEqual() at testdata/underscore/underscore.php:724 +ERROR undefinedMethod: Call to undefined method {object}->isEqual() at testdata/underscore/underscore.php:724 if(is_object($b) && isset($b->isEqual)) return self::_wrap($b->isEqual($a)); ^^^^^^^ -MAYBE arrayAccess: Array access to non-array type \__|mixed|null at testdata/underscore/underscore.php:725 - if(is_array($a) && array_key_exists('isEqual', $a)) return self::_wrap($a['isEqual']($b)); - ^^ +WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:728 + if(count($a) !== count($b)) return self::_wrap(false); + ^^^^^ +WARNING notSafetyCall: potential not safety call in function keys signature of param collection at testdata/underscore/underscore.php:731 + $keys_equal = $__->isEqual($__->keys($a), $__->keys($b)); + ^^ +WARNING notSafetyCall: potential not safety call in function values signature of param collection at testdata/underscore/underscore.php:732 + $values_equal = $__->isEqual($__->values($a), $__->values($b)); + ^^ +WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:736 + return self::_wrap(false); + ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function is_nan signature of param num at testdata/underscore/underscore.php:772 return self::_wrap((is_int($item) || is_float($item)) && !is_nan($item) && !is_infinite($item)); ^^^^^ @@ -184,9 +295,15 @@ ERROR undefinedProperty: Property {mixed}->_mixins does not exist at testdata/ ERROR undefinedProperty: Property {mixed}->_mixins does not exist at testdata/underscore/underscore.php:853 $mixins =& self::getInstance()->_mixins; ^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter callback of function call_user_func_array at testdata/underscore/underscore.php:854 + return call_user_func_array($mixins[$name], $arguments); + ^^^^^^^^^^^^^^ ERROR undefinedProperty: Property {mixed}->_mixins does not exist at testdata/underscore/underscore.php:859 $mixins =& self::getInstance()->_mixins; ^^^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter callback of function call_user_func_array at testdata/underscore/underscore.php:861 + return call_user_func_array($mixins[$name], $arguments); + ^^^^^^^^^^^^^^ ERROR undefinedProperty: Property {mixed}->_template_settings does not exist at testdata/underscore/underscore.php:882 $_template_settings =& self::getInstance()->_template_settings; ^^^^^^^^^^^^^^^^^^ @@ -205,18 +322,27 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:913 preg_match_all($ts['escape'], $code, $vars, PREG_SET_ORDER); ^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function trim at testdata/underscore/underscore.php:916 + $echo = $class_name::TEMPLATE_OPEN_TAG . ' echo htmlentities(' . trim($var[1]) . '); ' . $class_name::TEMPLATE_CLOSE_TAG; + ^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter pattern of function preg_match_all at testdata/underscore/underscore.php:920 preg_match_all($ts['interpolate'], $code, $vars, PREG_SET_ORDER); ^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:920 preg_match_all($ts['interpolate'], $code, $vars, PREG_SET_ORDER); ^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function trim at testdata/underscore/underscore.php:923 + $echo = $class_name::TEMPLATE_OPEN_TAG . ' echo ' . trim($var[1]) . '; ' . $class_name::TEMPLATE_CLOSE_TAG; + ^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter pattern of function preg_match_all at testdata/underscore/underscore.php:927 preg_match_all($ts['evaluate'], $code, $vars, PREG_SET_ORDER); ^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:927 preg_match_all($ts['evaluate'], $code, $vars, PREG_SET_ORDER); ^^^^^ +WARNING notSafetyCall: potential not safety array access in parameter string of function trim at testdata/underscore/underscore.php:930 + $echo = $class_name::TEMPLATE_OPEN_TAG . trim($var[1]) . $class_name::TEMPLATE_CLOSE_TAG; + ^^^^^^^ MAYBE deprecated: Call to deprecated function create_function (since: 7.2, reason: Use anonymous functions instead, removed: 8.0) at testdata/underscore/underscore.php:940 $func = create_function('$context', $code); ^^^^^^^^^^^^^^^ @@ -253,6 +379,12 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1037 return call_user_func_array($wrapper, $args); ^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1049 + $args[0] = call_user_func_array($function, $args); + ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function md5 signature of param string when calling function \mt_rand at testdata/underscore/underscore.php:1062 + $key = md5(mt_rand()); + ^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1068 if($_instance->_aftered[$key] >= $count) return call_user_func_array($function, func_get_args()); ^^^^^^^^^ From 7625e350e4a4a757eedf6fb71b9eec6d2b7c3dc5 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Fri, 4 Apr 2025 05:21:55 +0300 Subject: [PATCH 27/36] test fixes and better error naming --- src/linter/and_walker.go | 60 ++++++++++++++++++++++++++ src/linter/block_linter.go | 2 +- src/tests/checkers/not_safety_test.go | 56 ++++++++++++++++++++++++ src/tests/checkers/null_safety_test.go | 58 +++++++++++++++++++++++-- src/tests/checkers/oop_test.go | 10 ++--- 5 files changed, 177 insertions(+), 9 deletions(-) diff --git a/src/linter/and_walker.go b/src/linter/and_walker.go index c521459e..3655d5ce 100644 --- a/src/linter/and_walker.go +++ b/src/linter/and_walker.go @@ -45,6 +45,9 @@ func (a *andWalker) EnterNode(w ir.Node) (res bool) { case *ir.ParenExpr: return true + case *ir.SimpleVar: + a.handleVariableCondition(n) + case *ir.FunctionCallExpr: // If the absence of a function or method is being // checked, then nothing needs to be done. @@ -244,6 +247,63 @@ func (a *andWalker) EnterNode(w ir.Node) (res bool) { return res } +func (a *andWalker) handleVariableCondition(variable *ir.SimpleVar) { + if !a.b.ctx.sc.HaveVar(variable) { + return + } + + currentType := a.exprType(variable) // nolint:staticcheck + if a.inNot { + currentType = a.exprTypeInContext(a.trueContext, variable) + } else { + currentType = a.exprTypeInContext(a.falseContext, variable) + } + + var trueType, falseType types.Map + + // First, handle "null": if currentType contains "null", then in the true branch we remove it, + // and in the false branch we narrow to "null" + if currentType.Contains("null") { + trueType = currentType.Clone().Erase("null") + falseType = types.NewMap("null") + } else { + trueType = currentType.Clone() + falseType = currentType.Clone() + } + + // Next, handle booleans + // If currentType contains any boolean-related literal ("bool", "true", "false"), + // then we want to narrow them: + // - If there are non-boolean parts (e.g. "User") in the union, they are always truthy + // In that case, true branch becomes nonBool ∪ {"true"} and false branch becomes {"false"} + // - If only the boolean part is present, then narrow to {"true"} and {"false"} respectively + if currentType.Contains("bool") || currentType.Contains("true") || currentType.Contains("false") { + nonBool := currentType.Clone().Erase("bool").Erase("true").Erase("false") + if nonBool.Len() > 0 { + if currentType.Contains("bool") || currentType.Contains("true") { + trueType = nonBool.Union(types.NewMap("true")) + } else { + trueType = nonBool + } + falseType = types.NewMap("false") + } else { + trueType = types.NewMap("true") + falseType = types.NewMap("false") + } + } + + // Note: For other types (e.g. int, string, array), our type system doesn't include literal values, + // so we don't perform additional narrowing + + // If we are in the "not" context (i.e. if(!$variable)), swap the branches + if a.inNot { + trueType, falseType = falseType, trueType + } + + a.trueContext.sc.ReplaceVar(variable, trueType, "type narrowing for "+variable.Name, meta.VarAlwaysDefined) + a.falseContext.sc.ReplaceVar(variable, falseType, "type narrowing for "+variable.Name, meta.VarAlwaysDefined) +} + func (a *andWalker) handleTypeCheckCondition(expectedType string, args []ir.Node) { for _, arg := range args { argument, ok := arg.(*ir.Argument) diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 71956663..9f25b8b9 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -1403,7 +1403,7 @@ func (b *blockLinter) checkSafetyCall(e ir.Node, typ types.Map, name string, suf switch { case reportFullName == "notNullSafetyPropertyFetch": b.report(e, LevelWarning, "notNullSafety"+suffix, - "attempt to access property that can be null") + "potential attempt to access property through null") return case reportFullName == "notNullSafetyVariable" || reportFullName == "notNullSafetyFunctionCall": b.report(e, LevelWarning, reportFullName, diff --git a/src/tests/checkers/not_safety_test.go b/src/tests/checkers/not_safety_test.go index 8ec3fdcc..eec6af5d 100644 --- a/src/tests/checkers/not_safety_test.go +++ b/src/tests/checkers/not_safety_test.go @@ -430,3 +430,59 @@ class User{ } test.RunAndMatch() } + +func TestVariableCondition(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`name; +} else { + echo "User not found." . $user->name; +} +`) + test.Expect = []string{ + "potential not safety call when accessing property", + "Property {false}->name does not exist", + "potential not safety call when accessing property", + } + test.RunAndMatch() +} + +func TestVariableNotCondition(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`name; +} else { + echo "User not found." . $user->name; +} +`) + test.Expect = []string{ + "potential not safety call when accessing property", + "Property {false}->name does not exist", + "potential not safety call when accessing property", + } + test.RunAndMatch() +} diff --git a/src/tests/checkers/null_safety_test.go b/src/tests/checkers/null_safety_test.go index ba5159f3..14c40b1c 100644 --- a/src/tests/checkers/null_safety_test.go +++ b/src/tests/checkers/null_safety_test.go @@ -280,7 +280,7 @@ $user = null; echo $user->name; `) test.Expect = []string{ - "attempt to access property that can be null", + "potential attempt to access property through null", } test.RunAndMatch() } @@ -390,7 +390,7 @@ testValue(nullFunc()); test.RunAndMatch() } -func TestStaticCallNullSafetyThrowVariable(t *testing.T) { +func TestStaticCallNullSafetyThroughVariable(t *testing.T) { test := linttest.NewSuite(t) test.AddFile(`name; +} else { + echo "User not found." . $user->name; +} +`) + test.Expect = []string{ + "potential attempt to access property through null", + } + test.RunAndMatch() +} + +func TestVariableInConditionNullSafety(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`name; +} else { + echo "User not found." . $user->name; +} +`) + test.Expect = []string{ + "potential attempt to access property through null", + } + test.RunAndMatch() +} diff --git a/src/tests/checkers/oop_test.go b/src/tests/checkers/oop_test.go index 1fa4e37e..0856828a 100644 --- a/src/tests/checkers/oop_test.go +++ b/src/tests/checkers/oop_test.go @@ -289,7 +289,7 @@ $_ = WithProps::$int; test.Expect = []string{ `Class constant \WithProps::int does not exist`, `Property \WithProps::$int does not exist`, - `attempt to access property that can be null`, + `potential attempt to access property through null`, } test.RunAndMatch() @@ -348,8 +348,8 @@ $_ = WithProps::$int1; `Class constant \WithProps::int1 does not exist`, `Property \WithProps::$int does not exist`, `Property \WithProps::$int1 does not exist`, - `attempt to access property that can be null`, - `attempt to access property that can be null`, + `potential attempt to access property through null`, + `potential attempt to access property through null`, } test.RunAndMatch() @@ -1114,8 +1114,8 @@ function test3(?A $instance) { `) test.Expect = []string{ `Property {\A|null}->c does not exist`, - `attempt to access property that can be null`, - `attempt to access property that can be null`, + `potential attempt to access property through null`, + `potential attempt to access property through null`, } test.RunAndMatch() } From da60523ee48df64070a20dbb4d166322eeb07b7b Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Fri, 4 Apr 2025 19:13:40 +0300 Subject: [PATCH 28/36] variadic fix --- src/linter/block.go | 4 ++++ src/tests/checkers/basic_test.go | 2 -- .../golden/testdata/underscore/golden.txt | 24 ------------------- 3 files changed, 4 insertions(+), 26 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index ef61f834..8613aaec 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1222,6 +1222,10 @@ func (b *blockWalker) checkSimpleVarSafety(arg ir.Node, fn meta.FuncInfo, paramI } func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) bool { + if paramType.Empty() { + return true + } + var forcedVarType types.Map if varType.Len() > paramType.Len() { diff --git a/src/tests/checkers/basic_test.go b/src/tests/checkers/basic_test.go index e414d1db..3d457bcc 100644 --- a/src/tests/checkers/basic_test.go +++ b/src/tests/checkers/basic_test.go @@ -2219,8 +2219,6 @@ function f() { `possibly wrong order of arguments, min = 100, max = 99`, `possibly wrong order of arguments, min = 1, max = 0`, `possibly wrong order of arguments, min = 156, max = 119`, - `potential not safety access in parameter min of function random_int`, - `potential not safety access in parameter max of function random_int`, } test.RunAndMatch() } diff --git a/src/tests/golden/testdata/underscore/golden.txt b/src/tests/golden/testdata/underscore/golden.txt index 3ab9c919..1bd52d8f 100644 --- a/src/tests/golden/testdata/underscore/golden.txt +++ b/src/tests/golden/testdata/underscore/golden.txt @@ -25,9 +25,6 @@ WARNING notSafetyCall: potential not safety call in function first signature of WARNING notSafetyCall: potential not safety call in function map signature of param collection at testdata/underscore/underscore.php:161 if(!is_null($iterator)) $collection = $__->map($collection, $iterator); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:162 - if(count($collection) === 0) return self::_wrap(false); - ^^^^^ WARNING notSafetyCall: potential not safety call in function is_int signature of param value when calling function \array_search at testdata/underscore/underscore.php:164 return self::_wrap(is_int(array_search(true, $collection, false))); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,9 +52,6 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func signature of param callback at testdata/underscore/underscore.php:224 if(call_user_func($iterator, $val)) return $val; ^^^^^^^^^ -WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:226 - return self::_wrap(false); - ^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:248 if($n === 0) return self::_wrap(array()); ^^^^^^^ @@ -232,18 +226,6 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_key_exists signature of param key at testdata/underscore/underscore.php:703 return self::_wrap(array_key_exists($key, $collection)); ^^^^ -WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:713 - if($a === $b) return self::_wrap(true); - ^^^^ -WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:714 - if(gettype($a) !== gettype($b)) return self::_wrap(false); - ^^^^^ -WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:715 - if(is_callable($a) !== is_callable($b)) return self::_wrap(false); - ^^^^^ -WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:717 - if($a == $b) return self::_wrap(true); - ^^^^ ERROR undefinedProperty: Property {array}->isEqual does not exist at testdata/underscore/underscore.php:723 if(is_object($a) && isset($a->isEqual)) return self::_wrap($a->isEqual($b)); ^^^^^^^ @@ -256,18 +238,12 @@ ERROR undefinedProperty: Property {object}->isEqual does not exist at testdata ERROR undefinedMethod: Call to undefined method {object}->isEqual() at testdata/underscore/underscore.php:724 if(is_object($b) && isset($b->isEqual)) return self::_wrap($b->isEqual($a)); ^^^^^^^ -WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:728 - if(count($a) !== count($b)) return self::_wrap(false); - ^^^^^ WARNING notSafetyCall: potential not safety call in function keys signature of param collection at testdata/underscore/underscore.php:731 $keys_equal = $__->isEqual($__->keys($a), $__->keys($b)); ^^ WARNING notSafetyCall: potential not safety call in function values signature of param collection at testdata/underscore/underscore.php:732 $values_equal = $__->isEqual($__->values($a), $__->values($b)); ^^ -WARNING notSafetyCall: potential not safety access in parameter val of function _wrap at testdata/underscore/underscore.php:736 - return self::_wrap(false); - ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function is_nan signature of param num at testdata/underscore/underscore.php:772 return self::_wrap((is_int($item) || is_float($item)) && !is_nan($item) && !is_infinite($item)); ^^^^^ From 560eb353ce88d07be717f09af64a72c7068b9e14 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 8 Apr 2025 06:47:05 +0300 Subject: [PATCH 29/36] more cases --- src/linter/block.go | 38 ++++++---- src/solver/solver.go | 35 +++++++++ src/tests/checkers/not_safety_test.go | 45 +++++++++++ src/tests/golden/testdata/ctype/golden.txt | 3 - .../golden/testdata/embeddedrules/golden.txt | 9 --- .../golden/testdata/flysystem/golden.txt | 21 +----- src/tests/golden/testdata/idn/golden.txt | 3 + src/tests/golden/testdata/math/golden.txt | 27 ------- src/tests/golden/testdata/mustache/golden.txt | 9 --- .../testdata/options-resolver/golden.txt | 24 ++---- .../golden/testdata/parsedown/golden.txt | 75 +++++-------------- .../golden/testdata/phprocksyd/golden.txt | 6 -- src/tests/golden/testdata/qrcode/golden.txt | 12 +++ .../testdata/twitter-api-php/golden.txt | 12 +-- .../golden/testdata/underscore/golden.txt | 33 ++------ 15 files changed, 159 insertions(+), 193 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index 8613aaec..4c679c55 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1226,19 +1226,24 @@ func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) b return true } - var forcedVarType types.Map + var forcedVarType = types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", varType, solver.ResolverMap{})) - if varType.Len() > paramType.Len() { - forcedVarType = types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", varType, solver.ResolverMap{})) - if forcedVarType.Len() > paramType.Len() { - return false + // Attempt to merge union types if one is a subclass/implementation of the other + if forcedVarType.Len() > 1 { + metaInfo := b.r.metaInfo() + forcedVarType = solver.MergeUnionTypes(metaInfo, forcedVarType) + } + + if forcedVarType.Len() > paramType.Len() { + if paramType.Contains(types.WrapArrayOf("mixed")) || paramType.Contains("mixed") { + return true } - varType = forcedVarType + return false } - isVarBoolean := varType.IsBoolean() - isClass := varType.IsClass() - varClassName := varType.String() + isVarBoolean := forcedVarType.IsBoolean() + isClass := forcedVarType.IsClass() + varClassName := forcedVarType.String() for _, param := range paramType.Keys() { // boolean case @@ -1251,7 +1256,7 @@ func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) b } // exact match - if varType.Contains(param) { + if forcedVarType.Contains(param) { return true } @@ -1271,11 +1276,18 @@ func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) b } } - if forcedVarType.Empty() { - forcedVarType = types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", varType, solver.ResolverMap{})) - } forcedParamType := types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", paramType, solver.ResolverMap{})) + // TODO: This is bullshit because we have no good type inferring for arrays: bool[1] will be bool[]! !not bool! + if strings.Contains(forcedParamType.String(), "[") { + idx := strings.Index(forcedParamType.String(), "[") + arrayType := forcedParamType.String()[:idx] //nolint:gocritic + return forcedParamType.Contains(arrayType) + } else if strings.Contains(varType.String(), "[") { + idx := strings.Index(varType.String(), "[") + arrayType := varType.String()[:idx] //nolint:gocritic + return forcedParamType.Contains(arrayType) + } return !forcedParamType.Intersect(forcedVarType).Empty() } diff --git a/src/solver/solver.go b/src/solver/solver.go index cc9b4ed4..93c82d5b 100644 --- a/src/solver/solver.go +++ b/src/solver/solver.go @@ -502,6 +502,41 @@ func ImplementsAbstract(info *meta.Info, className, abstractName string) bool { return false } +// IsMoreSpecific returns true if type key1 is more specific than key2. +// That is, key1 extends/implements key2 (or in abstract sense as well) +func IsMoreSpecific(metaInfo *meta.Info, key1, key2 string) bool { + return Implements(metaInfo, key1, key2) || + ImplementsAbstract(metaInfo, key1, key2) +} + +// MergeUnionTypes iteratively merges union types in the Map using specific-ness +func MergeUnionTypes(metaInfo *meta.Info, m types.Map) types.Map { + changed := true + // Iteratively try to merge the union until no more changes occur + for changed { + changed = false + // Always re-read keys after modifications + keys := m.Keys() + outer: + for i := 0; i < len(keys); i++ { + for j := i + 1; j < len(keys); j++ { + key1 := keys[i] + key2 := keys[j] + if IsMoreSpecific(metaInfo, key1, key2) { + m = m.Erase(key2) + changed = true + break outer + } else if IsMoreSpecific(metaInfo, key2, key1) { + m = m.Erase(key1) + changed = true + break outer + } + } + } + } + return m +} + func implements(info *meta.Info, className, interfaceName string, visited map[string]struct{}) bool { if className == interfaceName { return true diff --git a/src/tests/checkers/not_safety_test.go b/src/tests/checkers/not_safety_test.go index eec6af5d..3aa69fb7 100644 --- a/src/tests/checkers/not_safety_test.go +++ b/src/tests/checkers/not_safety_test.go @@ -486,3 +486,48 @@ if (!$user) { } test.RunAndMatch() } + +func TestSelfNewInstanceHandlerWithAbstract(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`type = $type; + $this->handler = $handler; + } + + // Factory method for creating a task with a handler. + public static function newWithHandler(string $type, TaskHandler $handler): self { + return new self($type, $handler); + } +} + +// Concrete task handler extending the abstract TaskHandler. +class ConcreteTaskHandler extends TaskHandler { + // Factory method for creating an instance of ConcreteTaskHandler. + public static function create(): self { + return new self(); + } +} + +$handler = ConcreteTaskHandler::create(); +$task = Task::newWithHandler("example_task", $handler); + +`) + test.Expect = []string{ + "Missing PHPDoc for \\Task::newWithHandler public method", + "Missing PHPDoc for \\ConcreteTaskHandler::create public method", + } + test.RunAndMatch() +} diff --git a/src/tests/golden/testdata/ctype/golden.txt b/src/tests/golden/testdata/ctype/golden.txt index aee69001..df4b4157 100644 --- a/src/tests/golden/testdata/ctype/golden.txt +++ b/src/tests/golden/testdata/ctype/golden.txt @@ -49,9 +49,6 @@ WARNING notSafetyCall: potential not safety call in function preg_match signatur WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:196 return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text); ^^^^^ -WARNING notSafetyCall: potential not safety call in function is_int signature of param value at testdata/ctype/ctype.php:213 - if (!\is_int($int)) { - ^^^^ WARNING notSafetyCall: potential not safety call in function chr signature of param codepoint at testdata/ctype/ctype.php:225 return \chr($int); ^^^^ diff --git a/src/tests/golden/testdata/embeddedrules/golden.txt b/src/tests/golden/testdata/embeddedrules/golden.txt index 2d092ada..fb4df175 100644 --- a/src/tests/golden/testdata/embeddedrules/golden.txt +++ b/src/tests/golden/testdata/embeddedrules/golden.txt @@ -76,18 +76,9 @@ WARNING bitwiseOps: Used & bitwise operator over bool operands, perhaps && is in WARNING bitwiseOps: Used | bitwise operator over bool operands, perhaps || is intended? at testdata/embeddedrules/bitwiseOps.php:9 $_ = (($x == 1) | ($x == 2)); // Bad 2 ^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function in_array signature of param haystack when calling function \array_keys at testdata/embeddedrules/callSimplify.php:7 - $_ = in_array('abc', array_keys($array)); // bad - ^^^^^^^^^^^^^^^^^^ MAYBE callSimplify: Could simplify to array_key_exists('abc', $array) at testdata/embeddedrules/callSimplify.php:7 $_ = in_array('abc', array_keys($array)); // bad ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function in_array signature of param haystack when calling function \array_keys at testdata/embeddedrules/callSimplify.php:9 - $_ = in_array('abc', array_keys($array), true); // don't touch, has 3rd arg - ^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function in_array signature of param haystack when calling function \array_keys at testdata/embeddedrules/callSimplify.php:10 - $_ = in_array('abc', array_keys($array), false); // don't touch, has 3rd arg - ^^^^^^^^^^^^^^^^^^ MAYBE callSimplify: Could simplify to $str[$index] at testdata/embeddedrules/callSimplify.php:14 $_ = substr($str, $index, 1); ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/flysystem/golden.txt b/src/tests/golden/testdata/flysystem/golden.txt index 9a4923f9..2268ef4c 100644 --- a/src/tests/golden/testdata/flysystem/golden.txt +++ b/src/tests/golden/testdata/flysystem/golden.txt @@ -40,9 +40,6 @@ MAYBE callSimplify: Could simplify to $permissions[0] at testdata/flysystem/sr WARNING notSafetyCall: potential not safety call in function strtr signature of param str at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:569 $permissions = strtr($permissions, $map); ^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function array_sum signature of param array when calling function \str_split at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:576 - return array_sum(str_split($part)); - ^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function str_split signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:576 return array_sum(str_split($part)); ^^^^^ @@ -73,9 +70,6 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:156 $response = ftp_raw($this->connection, "OPTS UTF8 ON"); ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function substr at testdata/flysystem/src/Adapter/Ftp.php:157 - if (substr($response[0], 0, 3) !== '200') { - ^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:173 ftp_set_option($this->connection, FTP_USEPASVADDRESS, ! $this->ignorePassiveAddress); ^^^^^^^^^^^^^^^^^ @@ -244,12 +238,6 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_chdir signature of param directory at testdata/flysystem/src/Adapter/Ftpd.php:15 if (@ftp_chdir($this->getConnection(), $path) === true) { ^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function substr at testdata/flysystem/src/Adapter/Ftpd.php:25 - if (substr($object[1], 0, 5) === "ftpd:") { - ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter item of function normalizeObject at testdata/flysystem/src/Adapter/Ftpd.php:29 - return $this->normalizeObject($object[1], ''); - ^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_rawlist signature of param directory at testdata/flysystem/src/Adapter/Ftpd.php:37 $listing = ftp_rawlist($this->getConnection(), $directory, $recursive); ^^^^^^^^^^ @@ -358,9 +346,6 @@ WARNING notSafetyCall: potential not safety call in function getFilePath signatu WARNING notSafetyCall: potential not safety call in function normalizeFileInfo signature of param file at testdata/flysystem/src/Adapter/Local.php:287 $result[] = $this->normalizeFileInfo($file); ^^^^^ -WARNING notSafetyCall: potential not safety call in function array_filter signature of param array at testdata/flysystem/src/Adapter/Local.php:292 - return array_filter($result); - ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:300 $location = $this->applyPathPrefix($path); ^^^^^ @@ -490,6 +475,9 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function invokePluginOnFilesystem signature of param prefix at testdata/flysystem/src/MountManager.php:166 return $this->invokePluginOnFilesystem($method, $arguments, $prefix); ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function writeStream signature of param resource at testdata/flysystem/src/MountManager.php:192 + $result = $this->getFilesystem($prefixTo)->writeStream($to, $buffer, $config); + ^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter visibility of function setVisibility at testdata/flysystem/src/MountManager.php:243 return $filesystem->setVisibility($pathTo, $config['visibility']); ^^^^^^^^^^^^^^^^^^^^^ @@ -550,9 +538,6 @@ MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\UnreadableFileExcept WARNING notSafetyCall: potential not safety array access in parameter path of function pathinfo at testdata/flysystem/src/Util.php:27 $pathinfo += pathinfo($pathinfo['basename']); ^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function detectByContent signature of param content at testdata/flysystem/src/Util.php:186 - $mimeType = MimeType::detectByContent($content); - ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function pathinfo signature of param path at testdata/flysystem/src/Util.php:214 $listing[] = static::pathinfo($directory) + ['type' => 'dir']; ^^^^^^^^^^ diff --git a/src/tests/golden/testdata/idn/golden.txt b/src/tests/golden/testdata/idn/golden.txt index 17a6aecb..94ef9917 100644 --- a/src/tests/golden/testdata/idn/golden.txt +++ b/src/tests/golden/testdata/idn/golden.txt @@ -28,6 +28,9 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/idn/idn.php:119 $idna_info = array( +WARNING notSafetyCall: potential not safety call in function mb_chr signature of param codepoint at testdata/idn/idn.php:139 + $output .= mb_chr($code, 'utf-8'); + ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function mb_strlen signature of param string at testdata/idn/idn.php:152 $length = mb_strlen($input, 'utf-8'); ^^^^^^ diff --git a/src/tests/golden/testdata/math/golden.txt b/src/tests/golden/testdata/math/golden.txt index daa248f3..cec9e307 100644 --- a/src/tests/golden/testdata/math/golden.txt +++ b/src/tests/golden/testdata/math/golden.txt @@ -22,39 +22,18 @@ WARNING notSafetyCall: potential not safety call in function str_pad signature o WARNING notSafetyCall: potential not safety call in function ltrim signature of param string at testdata/math/src/BigInteger.php:105 $number = \ltrim($number, '0'); ^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter char of function charNotInAlphabet at testdata/math/src/BigInteger.php:163 - throw NumberFormatException::charNotInAlphabet($matches[0]); - ^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/math/src/BigInteger.php:435 new BigInteger($remainder) ^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function quotient signature of param that at testdata/math/src/BigInteger.php:649 - return $this->quotient($operand); - ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function dividedBy signature of param that at testdata/math/src/BigInteger.php:652 - return $this->dividedBy($operand, RoundingMode::UP); - ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function of signature of param value at testdata/math/src/BigInteger.php:742 $that = BigNumber::of($that); ^^^^^ -WARNING notSafetyCall: potential not safety call in function is_int signature of param value at testdata/math/src/BigNumber.php:64 - if (\is_int($value)) { - ^^^^^^ WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/math/src/BigNumber.php:74 if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) { ^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter number of function cleanUp at testdata/math/src/BigNumber.php:79 - $numerator = self::cleanUp($matches['integral']); - ^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function ltrim at testdata/math/src/BigNumber.php:80 - $denominator = \ltrim($matches['denominator'], '0'); - ^^^^^^^^^^^^^^^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$matches['fractional'] ?? ''` at testdata/math/src/BigNumber.php:90 $fractional = isset($matches['fractional']) ? $matches['fractional'] : ''; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter number of function cleanUp at testdata/math/src/BigNumber.php:107 - $integral = self::cleanUp($matches['integral']); - ^^^^^^^^^^^^^^^^^^^^ WARNING notSafetyCall: potential not safety call in function setlocale signature of param rest at testdata/math/src/BigNumber.php:131 \setlocale(LC_NUMERIC, $currentLocale); ^^^^^^^^^^^^^^ @@ -79,12 +58,6 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notSafetyCall: potential not safety call in function ltrim signature of param string at testdata/math/src/BigNumber.php:307 $number = \ltrim($number, '0'); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function quotient signature of param that at testdata/math/src/BigRational.php:354 - $numerator = $this->numerator->quotient($gcd); - ^^^^ -WARNING notSafetyCall: potential not safety call in function quotient signature of param that at testdata/math/src/BigRational.php:355 - $denominator = $this->denominator->quotient($gcd); - ^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function minus signature of param that at testdata/math/src/BigRational.php:365 return $this->minus($that)->getSign(); ^^^^^ diff --git a/src/tests/golden/testdata/mustache/golden.txt b/src/tests/golden/testdata/mustache/golden.txt index cdde65e6..79d84ec9 100644 --- a/src/tests/golden/testdata/mustache/golden.txt +++ b/src/tests/golden/testdata/mustache/golden.txt @@ -121,9 +121,6 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING unused: Variable $keystr is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/mustache/src/Mustache/Compiler.php:289 $keystr = var_export($key, true); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function var_export signature of param value when calling function \substr at testdata/mustache/src/Mustache/Compiler.php:373 - $source = var_export(substr($this->source, $start, $end - $start), true); - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function getFindMethod signature of param id at testdata/mustache/src/Mustache/Compiler.php:556 $method = $this->getFindMethod($name); ^^^^^ @@ -205,18 +202,12 @@ MAYBE callSimplify: Could simplify to $this->stack[] = $value at testdata/must MAYBE callSimplify: Could simplify to $this->blockStack[] = $value at testdata/mustache/src/Mustache/Context.php:49 array_push($this->blockStack, $value); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function array_shift signature of param array at testdata/mustache/src/Mustache/Context.php:130 - $first = array_shift($chunks); - ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:131 $value = $this->findVariableInStack($first, $this->stack); ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:138 $value = $this->findVariableInStack($chunk, array($value)); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function array_shift signature of param array at testdata/mustache/src/Mustache/Context.php:162 - $first = array_shift($chunks); - ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function findVariableInStack signature of param id at testdata/mustache/src/Mustache/Context.php:174 $value = $this->findVariableInStack($chunk, array($value)); ^^^^^^ diff --git a/src/tests/golden/testdata/options-resolver/golden.txt b/src/tests/golden/testdata/options-resolver/golden.txt index dc4ae991..49dbbaca 100644 --- a/src/tests/golden/testdata/options-resolver/golden.txt +++ b/src/tests/golden/testdata/options-resolver/golden.txt @@ -43,24 +43,12 @@ WARNING invalidDocblock: @param for non-existing argument $version at testdata/o WARNING invalidDocblock: @param for non-existing argument $message at testdata/options-resolver/OptionsResolver.php:426 * @param string|\Closure $message The deprecation message to use ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:870 - throw new UndefinedOptionsException(sprintf((\count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Defined options are: "%s".', $this->formatOptions(array_keys($diff)), implode('", "', array_keys($clone->defined)))); - ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:886 - throw new MissingOptionsException(sprintf(\count($diff) > 1 ? 'The required options "%s" are missing.' : 'The required option "%s" is missing.', $this->formatOptions(array_keys($diff)))); - ^^^^^^^^^^^^^^^^^ WARNING notSafetyCall: potential not safety call in function offsetGet signature of param option at testdata/options-resolver/OptionsResolver.php:895 $clone->offsetGet($option); ^^^^^^^ MAYBE complexity: Too big method: more than 150 lines at testdata/options-resolver/OptionsResolver.php:917 public function offsetGet($option, bool $triggerDeprecation = true) ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:947 - throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); - ^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:974 - throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); - ^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1000 if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { ^^^^^ @@ -73,9 +61,6 @@ WARNING notSafetyCall: potential not safety call in function verifyTypes signatu WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1000 if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { ^^^^^^ -WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:1076 - throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); - ^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notSafetyCall: potential not safety array access in parameter package of function trigger_deprecation at testdata/options-resolver/OptionsResolver.php:1090 trigger_deprecation($deprecation['package'], $deprecation['version'], strtr($message, ['%name%' => $option])); ^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,18 +70,21 @@ WARNING notSafetyCall: potential not safety array access in parameter version of WARNING notSafetyCall: potential not safety call in function strtr signature of param str at testdata/options-resolver/OptionsResolver.php:1090 trigger_deprecation($deprecation['package'], $deprecation['version'], strtr($message, ['%name%' => $option])); ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function formatOptions signature of param options when calling function \array_keys at testdata/options-resolver/OptionsResolver.php:1099 - throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); - ^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $invalidTypes in PHPDoc, 'array' type hint too generic at testdata/options-resolver/OptionsResolver.php:1123 private function verifyTypes(string $type, $value, array &$invalidTypes, int $level = 0): bool ^^^^^^^^^^^ WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1130 if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { ^^^^^ +WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1130 + if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { + ^^^^ WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1130 if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { ^^^^^ +WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1130 + if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { + ^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function get_class signature of param object at testdata/options-resolver/OptionsResolver.php:1221 return \get_class($value); ^^^^^^ diff --git a/src/tests/golden/testdata/parsedown/golden.txt b/src/tests/golden/testdata/parsedown/golden.txt index 7063620b..09f24541 100644 --- a/src/tests/golden/testdata/parsedown/golden.txt +++ b/src/tests/golden/testdata/parsedown/golden.txt @@ -4,9 +4,6 @@ MAYBE implicitModifiers: Specify the access modifier for \Parsedown::text meth WARNING notSafetyCall: potential not safety call in function trim signature of param string at testdata/parsedown/parsedown.php:46 $text = trim($text, "\n"); ^^^^^ -WARNING notSafetyCall: potential not safety call in function linesElements signature of param lines at testdata/parsedown/parsedown.php:52 - return $this->linesElements($lines); - ^^^^^^ MAYBE implicitModifiers: Specify the access modifier for \Parsedown::setBreaksEnabled method explicitly at testdata/parsedown/parsedown.php:59 function setBreaksEnabled($breaksEnabled) ^^^^^^^^^^^^^^^^ @@ -124,12 +121,6 @@ MAYBE typeHint: Specify the type for the parameter $CurrentBlock in PHPDoc, 'a WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:578 if (preg_match('/^('.$pattern.'([ ]++|$))(.*+)/', $Line['text'], $matches)) ^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:580 - $contentIndent = strlen($matches[2]); - ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function substr at testdata/parsedown/parsedown.php:585 - $matches[1] = substr($matches[1], 0, -$contentIndent); - ^^^^^^^^^^^ WARNING notSafetyCall: potential not safety array access in parameter haystack of function strstr at testdata/parsedown/parsedown.php:593 $markerWithoutWhitespace = strstr($matches[1], ' ', true); ^^^^^^^^^^^ @@ -157,6 +148,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:659 and preg_match('/^'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) ^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:659 + and preg_match('/^'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) + ^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$matches[1] ?? ''` at testdata/parsedown/parsedown.php:674 $text = isset($matches[1]) ? $matches[1] : ''; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -211,9 +205,6 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:836 if (preg_match('/^<[\/]?+(\w*)(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+(\/)?>/', $Line['text'], $matches)) ^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strtolower at testdata/parsedown/parsedown.php:838 - $element = strtolower($matches[1]); - ^^^^^^^^^^^ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings at testdata/parsedown/parsedown.php:840 if (in_array($element, $this->textLevelElements)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,9 +220,6 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access MAYBE regexpSimplify: May re-write '/^\[(.+?)\]:[ ]*+?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/' as '/^\[(.+?)\]: *+?(?: +["'(](.+)["')])? *+$/' at testdata/parsedown/parsedown.php:875 and preg_match('/^\[(.+?)\]:[ ]*+?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/', $Line['text'], $matches) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strtolower at testdata/parsedown/parsedown.php:877 - $id = strtolower($matches[1]); - ^^^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$matches[3] ?? null` at testdata/parsedown/parsedown.php:881 'title' => isset($matches[3]) ? $matches[3] : null, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -274,6 +262,9 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1093 protected function paragraphContinue($Line, array $Block) ^^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function lineElements signature of param nonNestables at testdata/parsedown/parsedown.php:1132 + return $this->elements($this->lineElements($text, $nonNestables)); + ^^^^^^^^^^^^^ WARNING notSafetyCall: potential not safety call in function strpbrk signature of param string at testdata/parsedown/parsedown.php:1149 while ($excerpt = strpbrk($text, $this->inlineMarkerList)) ^^^^^ @@ -304,27 +295,18 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access MAYBE regexpSimplify: May re-write '/[ ]*+\n/' as '/ *+\n/' at testdata/parsedown/parsedown.php:1265 $text = preg_replace('/[ ]*+\n/', ' ', $text); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1268 - 'extent' => strlen($matches[0]), - ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:1284 if (strpos($Excerpt['text'], '>') !== false ^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1285 and preg_match("/^<((mailto:)?$commonMarkEmail)>/i", $Excerpt['text'], $matches) ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1295 - 'extent' => strlen($matches[0]), - ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1316 if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1320 elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1330 - 'extent' => strlen($matches[0]), - ^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:1333 'handler' => array( ^ @@ -334,36 +316,27 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1408 if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1412 - $extent += strlen($matches[0]); - ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1414 $remainder = substr($remainder, $extent); ^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1421 if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) ^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1421 + if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) + ^^^^^^^^ MAYBE regexpSimplify: May re-write '/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/' as '/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?: +("[^"]*+"|'[^']*+'))?\s*+[)]/' at testdata/parsedown/parsedown.php:1421 if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function substr at testdata/parsedown/parsedown.php:1427 - $Element['attributes']['title'] = substr($matches[2], 1, - 1); - ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1430 - $extent += strlen($matches[0]); - ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1434 if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1436 - $definition = strlen($matches[1]) ? $matches[1] : $Element['handler']['argument']; - ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1434 + if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) + ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strtolower signature of param string at testdata/parsedown/parsedown.php:1437 $definition = strtolower($definition); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1439 - $extent += strlen($matches[0]); - ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter haystack of function strpos at testdata/parsedown/parsedown.php:1465 if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) ^^^^^^^^^^^^^^^^ @@ -373,21 +346,18 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access MAYBE regexpSimplify: May re-write '/^<\/\w[\w-]*+[ ]*+>/s' as '/^<\/\w[\w-]*+ *+>/s' at testdata/parsedown/parsedown.php:1470 if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1474 - 'extent' => strlen($matches[0]), - ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1478 if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1482 - 'extent' => strlen($matches[0]), - ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1478 + if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) + ^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1486 if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1490 - 'extent' => strlen($matches[0]), - ^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1486 + if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches)) + ^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:1497 if (substr($Excerpt['text'], 1, 1) !== ' ' and strpos($Excerpt['text'], ';') !== false ^^^^^^^^^^^^^^^^ @@ -400,15 +370,9 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1498 and preg_match('/^&(#?+[0-9a-zA-Z]++);/', $Excerpt['text'], $matches) ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1502 - 'extent' => strlen($matches[0]), - ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1516 if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1519 - 'extent' => strlen($matches[0]), - ^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:1522 'handler' => array( ^ @@ -427,9 +391,6 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1562 if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w++:\/{2}[^ >]++)>/i', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function strlen at testdata/parsedown/parsedown.php:1567 - 'extent' => strlen($matches[0]), - ^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Element in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1591 protected function handle(array $Element) ^^^^^^ diff --git a/src/tests/golden/testdata/phprocksyd/golden.txt b/src/tests/golden/testdata/phprocksyd/golden.txt index 30b55e5b..45c428eb 100644 --- a/src/tests/golden/testdata/phprocksyd/golden.txt +++ b/src/tests/golden/testdata/phprocksyd/golden.txt @@ -49,9 +49,6 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function pcntl_wexitstatus signature of param status at testdata/phprocksyd/Phprocksyd.php:241 $Res->retcode = pcntl_wexitstatus($status); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function array_pop signature of param array at testdata/phprocksyd/Phprocksyd.php:269 - $this->read_buf[$stream_id] = array_pop($requests); - ^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rtrim signature of param string at testdata/phprocksyd/Phprocksyd.php:272 $req = rtrim($req); ^^^^ @@ -181,9 +178,6 @@ WARNING notSafetyCall: potential not safety call in function stream_set_blocking WARNING notSafetyCall: potential not safety call in function stream_set_timeout signature of param stream at testdata/phprocksyd/Simple.php:75 stream_set_timeout($client, 1); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function array_pop signature of param array at testdata/phprocksyd/Simple.php:113 - $this->read_buf[$stream_id] = array_pop($requests); - ^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rtrim signature of param string at testdata/phprocksyd/Simple.php:116 $res = json_decode(rtrim($req), true); ^^^^ diff --git a/src/tests/golden/testdata/qrcode/golden.txt b/src/tests/golden/testdata/qrcode/golden.txt index 4dcd83be..0c828bc3 100644 --- a/src/tests/golden/testdata/qrcode/golden.txt +++ b/src/tests/golden/testdata/qrcode/golden.txt @@ -1,6 +1,12 @@ MAYBE missingPhpdoc: Missing PHPDoc for \QRCode::output_image public method at testdata/qrcode/qrcode.php:45 public function output_image() { ^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function imagepng signature of param image at testdata/qrcode/qrcode.php:49 + imagepng($image); + ^^^^^^ +WARNING notSafetyCall: potential not safety call in function imagedestroy signature of param image at testdata/qrcode/qrcode.php:50 + imagedestroy($image); + ^^^^^^ MAYBE missingPhpdoc: Missing PHPDoc for \QRCode::render_image public method at testdata/qrcode/qrcode.php:53 public function render_image() { ^^^^^^^^^^^^ @@ -19,6 +25,9 @@ MAYBE ternarySimplify: Could rewrite as `$this->options['bc'] ?? 'FFFFFF'` at WARNING notSafetyCall: potential not safety call in function imagefill signature of param image at testdata/qrcode/qrcode.php:61 imagefill($image, 0, 0, $bgcolor); ^^^^^^ +WARNING notSafetyCall: potential not safety call in function imagefill signature of param color at testdata/qrcode/qrcode.php:61 + imagefill($image, 0, 0, $bgcolor); + ^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$this->options['fc'] ?? '000000'` at testdata/qrcode/qrcode.php:63 $fgcolor = (isset($this->options['fc']) ? $this->options['fc'] : '000000'); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,6 +43,9 @@ WARNING notSafetyCall: potential not safety call in function imagefilledrectangl WARNING notSafetyCall: potential not safety call in function imagefilledrectangle signature of param y1 at testdata/qrcode/qrcode.php:93 imagefilledrectangle($image, $rx, $ry, $rx + $rw - 1, $ry + $rh - 1, $mc); ^^^ +WARNING notSafetyCall: potential not safety call in function imagefilledrectangle signature of param color at testdata/qrcode/qrcode.php:93 + imagefilledrectangle($image, $rx, $ry, $rx + $rw - 1, $ry + $rh - 1, $mc); + ^^^ WARNING notSafetyCall: potential not safety call in function hexdec signature of param hex_string when calling function \substr at testdata/qrcode/qrcode.php:134 $r = hexdec(substr($color, 0, 2)); ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/twitter-api-php/golden.txt b/src/tests/golden/testdata/twitter-api-php/golden.txt index 78e73125..633a6101 100644 --- a/src/tests/golden/testdata/twitter-api-php/golden.txt +++ b/src/tests/golden/testdata/twitter-api-php/golden.txt @@ -22,6 +22,12 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing WARNING notSafetyCall: potential not safety array access in parameter string of function urldecode at testdata/twitter-api-php/TwitterAPIExchange.php:239 $oauth[$split[0]] = urldecode($split[1]); ^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:253 + $composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret); + ^^^^^^^^^^^^^^^^ +WARNING notSafetyCall: potential not safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:253 + $composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret); + ^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notSafetyCall: potential not safety call in function base64_encode signature of param string when calling function \hash_hmac at testdata/twitter-api-php/TwitterAPIExchange.php:254 $oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,9 +40,6 @@ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings WARNING notSafetyCall: potential not safety call in function curl_setopt_array signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:312 curl_setopt_array($feed, $options); ^^^^^ -WARNING notSafetyCall: potential not safety call in function curl_setopt_array signature of param options at testdata/twitter-api-php/TwitterAPIExchange.php:312 - curl_setopt_array($feed, $options); - ^^^^^^^^ WARNING notSafetyCall: potential not safety call in function curl_exec signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:313 $json = curl_exec($feed); ^^^^^ @@ -61,9 +64,6 @@ WARNING notSafetyCall: potential not safety call in function rawurlencode signat WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:345 $return[] = rawurlencode($key) . '=' . rawurlencode($value); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function in_array signature of param needle at testdata/twitter-api-php/TwitterAPIExchange.php:365 - if (in_array($key, array('oauth_consumer_key', 'oauth_nonce', 'oauth_signature', - ^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/twitter-api-php/TwitterAPIExchange.php:366 'oauth_signature_method', 'oauth_timestamp', 'oauth_token', 'oauth_version'))) { ^^^^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/underscore/golden.txt b/src/tests/golden/testdata/underscore/golden.txt index 1bd52d8f..40326d44 100644 --- a/src/tests/golden/testdata/underscore/golden.txt +++ b/src/tests/golden/testdata/underscore/golden.txt @@ -25,18 +25,9 @@ WARNING notSafetyCall: potential not safety call in function first signature of WARNING notSafetyCall: potential not safety call in function map signature of param collection at testdata/underscore/underscore.php:161 if(!is_null($iterator)) $collection = $__->map($collection, $iterator); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function is_int signature of param value when calling function \array_search at testdata/underscore/underscore.php:164 - return self::_wrap(is_int(array_search(true, $collection, false))); - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function array_search signature of param haystack at testdata/underscore/underscore.php:164 - return self::_wrap(is_int(array_search(true, $collection, false))); - ^^^^^^^^^^^ WARNING notSafetyCall: potential not safety call in function map signature of param collection at testdata/underscore/underscore.php:177 if(!is_null($iterator)) $collection = $__->map($collection, $iterator); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function is_bool signature of param value when calling function \array_search at testdata/underscore/underscore.php:181 - return self::_wrap(is_bool(array_search(false, $collection, false))); - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:193 $return = array(); ^^^^^^^ @@ -85,9 +76,6 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:363 $calculated = array(); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function is_bool signature of param value when calling function \array_search at testdata/underscore/underscore.php:366 - if(is_bool(array_search($val, $calculated, true))) { - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING unused: Variable $is_sorted is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/underscore/underscore.php:356 list($collection, $is_sorted, $iterator) = self::_wrapArgs(func_get_args(), 3); ^^^^^^^^^^ @@ -103,12 +91,6 @@ WARNING notSafetyCall: potential not safety call in function isArray signature o WARNING notSafetyCall: potential not safety call in function isArray signature of param item at testdata/underscore/underscore.php:385 if(!$__->isArray($next)) $next = str_split((string) $next); ^^^^^ -WARNING notSafetyCall: potential not safety call in function array_intersect signature of param arrays at testdata/underscore/underscore.php:387 - $return = array_intersect($return, $next); - ^^^^^ -WARNING notSafetyCall: potential not safety call in function is_bool signature of param value at testdata/underscore/underscore.php:420 - return self::_wrap((is_bool($key)) ? -1 : $key); - ^^^^ WARNING notSafetyCall: potential not safety call in function reject signature of param collection at testdata/underscore/underscore.php:441 $args = $__->reject($args, function($val) { ^^^^^ @@ -298,27 +280,24 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:913 preg_match_all($ts['escape'], $code, $vars, PREG_SET_ORDER); ^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function trim at testdata/underscore/underscore.php:916 - $echo = $class_name::TEMPLATE_OPEN_TAG . ' echo htmlentities(' . trim($var[1]) . '); ' . $class_name::TEMPLATE_CLOSE_TAG; - ^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter pattern of function preg_match_all at testdata/underscore/underscore.php:920 preg_match_all($ts['interpolate'], $code, $vars, PREG_SET_ORDER); ^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:920 preg_match_all($ts['interpolate'], $code, $vars, PREG_SET_ORDER); ^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function trim at testdata/underscore/underscore.php:923 - $echo = $class_name::TEMPLATE_OPEN_TAG . ' echo ' . trim($var[1]) . '; ' . $class_name::TEMPLATE_CLOSE_TAG; - ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match_all signature of param matches at testdata/underscore/underscore.php:920 + preg_match_all($ts['interpolate'], $code, $vars, PREG_SET_ORDER); + ^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter pattern of function preg_match_all at testdata/underscore/underscore.php:927 preg_match_all($ts['evaluate'], $code, $vars, PREG_SET_ORDER); ^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:927 preg_match_all($ts['evaluate'], $code, $vars, PREG_SET_ORDER); ^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function trim at testdata/underscore/underscore.php:930 - $echo = $class_name::TEMPLATE_OPEN_TAG . trim($var[1]) . $class_name::TEMPLATE_CLOSE_TAG; - ^^^^^^^ +WARNING notSafetyCall: potential not safety call in function preg_match_all signature of param matches at testdata/underscore/underscore.php:927 + preg_match_all($ts['evaluate'], $code, $vars, PREG_SET_ORDER); + ^^^^^ MAYBE deprecated: Call to deprecated function create_function (since: 7.2, reason: Use anonymous functions instead, removed: 8.0) at testdata/underscore/underscore.php:940 $func = create_function('$context', $code); ^^^^^^^^^^^^^^^ From 04763354478b48bc894acedf58db1f0984c5d433 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Wed, 9 Apr 2025 07:09:10 +0300 Subject: [PATCH 30/36] race condition --- src/linter/block.go | 288 +++++++++++++++++- src/solver/oop.go | 9 + src/tests/checkers/null_safety_test.go | 34 +++ .../golden/testdata/flysystem/golden.txt | 6 + 4 files changed, 324 insertions(+), 13 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index 4c679c55..2746463a 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1449,26 +1449,45 @@ func (b *blockWalker) getPropertyComputedType(expr ir.Node) (meta.ClassInfo, typ } } -func (b *blockWalker) checkPropertyFetchNotSafety(expr *ir.PropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { - // Recursively check the left part of the chain if it is also a property fetch. - if nested, ok := expr.Variable.(*ir.PropertyFetchExpr); ok { - b.checkPropertyFetchNotSafety(nested, fn, paramIndex, haveVariadic) +func (b *blockWalker) checkPropertyIntermediaryNodeSafety(node *ir.PropertyFetchExpr, propType types.Map, propName string) { + if types.IsTypeNullable(propType) { + b.report(node, LevelWarning, "notNullSafetyFunctionArgumentPropertyFetch", + "potential null dereference when accessing property '%s'", propName) + return } - - classInfo, propType := b.getPropertyComputedType(expr) - if classInfo.Name == "" || propType.Empty() { + if propType.Len() > 1 { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing property '%s': intermediary node is not a class", propName) return } - - prp, ok := expr.Property.(*ir.Identifier) - if !ok { + if !propType.IsClass() { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing property '%s': intermediary node is not a class", propName) return } +} - b.checkingPropertyFetchNullSafetyCondition(expr, propType, prp.Value, fn, paramIndex, haveVariadic) +func (b *blockWalker) checkPropertyIntermediaryVariableSafety(node *ir.SimpleVar, varType types.Map, varName string) { + if types.IsTypeNullable(varType) { + b.report(node, LevelWarning, "notNullSafetyFunctionArgumentPropertyFetch", + "potential null dereference when accessing property '%s'", varName) + return + } + if varType.Len() > 1 { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing property '%s': intermediary node is not a class", varName) + return + } + if !types.IsClass(varType.String()) { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing property '%s': intermediary node is not a class", varName) + return + } } -func (b *blockWalker) checkingPropertyFetchNullSafetyCondition( +// checkingPropertyFetchSafetyCondition verifies the safety of the final property fetch +// (the rightmost node in the chain) by checking null-safety and type compatibility +func (b *blockWalker) checkingPropertyFetchSafetyCondition( expr ir.Node, propType types.Map, prpName string, @@ -1479,6 +1498,7 @@ func (b *blockWalker) checkingPropertyFetchNullSafetyCondition( isPrpNullable := types.IsTypeNullable(propType) param := nullSafetyRealParamForCheck(fn, paramIndex, haveVariadic) paramType := param.Typ + if haveVariadic && paramIndex >= len(fn.Params)-1 { if types.IsTypeMixed(paramType) { return @@ -1507,6 +1527,248 @@ func (b *blockWalker) checkingPropertyFetchNullSafetyCondition( } } +// collectUnifiedPropertyFetchChain collects the entire chain of property fetches (instance or static) +// and returns a slice of nodes in the order: [rightmost property fetch, ..., base node (e.g. SimpleVar)] +func (b *blockWalker) collectUnifiedPropertyFetchChain(expr ir.Node) []ir.Node { + var chain []ir.Node + switch e := expr.(type) { + case *ir.PropertyFetchExpr: + cur := e + for { + chain = append(chain, cur) + if nested, ok := cur.Variable.(*ir.PropertyFetchExpr); ok { + cur = nested + } else { + chain = append(chain, cur.Variable) + break + } + } + case *ir.StaticPropertyFetchExpr: + cur := e + for { + chain = append(chain, cur) + if nested, ok := cur.Class.(*ir.StaticPropertyFetchExpr); ok { + cur = nested + } else { + chain = append(chain, cur.Class) + break + } + } + } + return chain +} + +// checkUnifiedPropertyFetchNotSafety combines checks for instance and static property access +// For the final (rightmost) node (the one being substituted), we check null and type safety +// and all intermediate nodes (except the base one) must be classes +// TODO: THIS IS MAIN!!! +func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { + chain := b.collectUnifiedPropertyFetchChain(expr) + if len(chain) == 0 { + return + } + + globalMetaInfo := b.linter.classParseState() + + var finalPropType types.Map + var finalPropName string + switch node := chain[0].(type) { + case *ir.PropertyFetchExpr: + propInfo := resolvePropertyFetch(b.ctx.sc, globalMetaInfo, b.ctx.customTypes, node, b.r.strictMixed) + if !propInfo.isFound { + return + } + ip, ok := node.Property.(*ir.Identifier) + if !ok { + return + } + finalPropType = propInfo.info.Typ + finalPropName = ip.Value + case *ir.StaticPropertyFetchExpr: + propInfo := resolveStaticPropertyFetch(globalMetaInfo, node) + if !propInfo.isFound { + return + } + sv, ok := node.Property.(*ir.SimpleVar) + if !ok { + return + } + finalPropType = propInfo.info.Info.Typ + finalPropName = sv.Name + default: + return + } + + b.checkingPropertyFetchSafetyCondition(expr, finalPropType, finalPropName, fn, paramIndex, haveVariadic) + + for i := 1; i < len(chain)-1; i++ { + switch node := chain[i].(type) { + case *ir.PropertyFetchExpr: + propInfo := resolvePropertyFetch(b.ctx.sc, globalMetaInfo, b.ctx.customTypes, node, b.r.strictMixed) + if !propInfo.isFound { + return + } + propType := propInfo.info.Typ + if types.IsTypeNullable(propType) { + b.report(node, LevelWarning, "notSafetyCall", + "potential null dereference when accessing property '%s'", propInfo.propertyNode.Value) + return + } + if propType.Len() > 1 || !propType.IsClass() { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing property '%s': intermediary node is not a class", propInfo.propertyNode.Value) + return + } + case *ir.SimpleVar: + varType, ok := b.ctx.sc.GetVarType(node) + if !ok { + return + } + if types.IsTypeNullable(varType) { + b.report(node, LevelWarning, "notSafetyCall", + "potential null dereference when accessing variable '%s'", node.Name) + return + } + if varType.Len() > 1 || !types.IsClass(varType.String()) { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing variable '%s': intermediary node is not a class", node.Name) + return + } + } + } +} + +// TODO: only for test racing +func (b *blockWalker) checkPropertyFetchNotSafety(expr *ir.PropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { + chain := b.collectUnifiedPropertyFetchChain(expr) + if len(chain) == 0 { + return + } + + globalMetaInfo := b.linter.classParseState() + + // --- Process final (rightmost) node (expected to be instance property fetch) + node, ok := chain[0].(*ir.PropertyFetchExpr) + if !ok { + return + } + propInfo := resolvePropertyFetch(b.ctx.sc, globalMetaInfo, b.ctx.customTypes, node, b.r.strictMixed) + if !propInfo.isFound { + return + } + ip, ok := node.Property.(*ir.Identifier) + if !ok { + return + } + finalPropType := propInfo.info.Typ + finalPropName := ip.Value + + b.checkingPropertyFetchSafetyCondition(expr, finalPropType, finalPropName, fn, paramIndex, haveVariadic) + + // --- Process intermediate nodes (excluding the base node) + for i := 1; i < len(chain)-1; i++ { + switch node := chain[i].(type) { + case *ir.PropertyFetchExpr: + propInfo := resolvePropertyFetch(b.ctx.sc, globalMetaInfo, b.ctx.customTypes, node, b.r.strictMixed) + if !propInfo.isFound { + return + } + propType := propInfo.info.Typ + if types.IsTypeNullable(propType) { + b.report(node, LevelWarning, "notSafetyCall", + "potential null dereference when accessing property '%s'", propInfo.propertyNode.Value) + return + } + if propType.Len() > 1 || !propType.IsClass() { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing property '%s': intermediary node is not a class", propInfo.propertyNode.Value) + return + } + case *ir.SimpleVar: + varType, ok := b.ctx.sc.GetVarType(node) + if !ok { + return + } + if types.IsTypeNullable(varType) { + b.report(node, LevelWarning, "notSafetyCall", + "potential null dereference when accessing variable '%s'", node.Name) + return + } + if varType.Len() > 1 || !types.IsClass(varType.String()) { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing variable '%s': intermediary node is not a class", node.Name) + return + } + } + } +} + +// TODO: only for test racing +func (b *blockWalker) checkStaticPropertyFetchNotSafety(expr *ir.StaticPropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { + chain := b.collectUnifiedPropertyFetchChain(expr) + if len(chain) == 0 { + return + } + + globalMetaInfo := b.linter.classParseState() + + // --- Process final (rightmost) node (expected to be static property fetch) + node, ok := chain[0].(*ir.StaticPropertyFetchExpr) + if !ok { + return + } + propInfo := resolveStaticPropertyFetch(globalMetaInfo, node) + if !propInfo.isFound { + return + } + sv, ok := node.Property.(*ir.SimpleVar) + if !ok { + return + } + finalPropType := propInfo.info.Info.Typ + finalPropName := sv.Name + + b.checkingPropertyFetchSafetyCondition(expr, finalPropType, finalPropName, fn, paramIndex, haveVariadic) + + // --- Process intermediate nodes (excluding the base node) + for i := 1; i < len(chain)-1; i++ { + switch node := chain[i].(type) { + case *ir.StaticPropertyFetchExpr: + propInfo := resolveStaticPropertyFetch(globalMetaInfo, node) + if !propInfo.isFound { + return + } + propType := propInfo.info.Info.Typ + if types.IsTypeNullable(propType) { + b.report(node, LevelWarning, "notSafetyCall", + "potential null dereference when accessing static property '%s'", propInfo.propertyName) + return + } + if propType.Len() > 1 || !propType.IsClass() { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing static property '%s': intermediary node is not a class", propInfo.propertyName) + return + } + case *ir.SimpleVar: + varType, ok := b.ctx.sc.GetVarType(node) + if !ok { + return + } + if types.IsTypeNullable(varType) { + b.report(node, LevelWarning, "notSafetyCall", + "potential null dereference when accessing variable '%s'", node.Name) + return + } + if varType.Len() > 1 || !types.IsClass(varType.String()) { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing variable '%s': intermediary node is not a class", node.Name) + return + } + } + } +} + +// TODO: old variant func (b *blockWalker) checkStaticPropertyFetchNullSafety(expr *ir.StaticPropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { // Recursively check the left part of the chain if it is also a property fetch. if nested, ok := expr.Class.(*ir.StaticPropertyFetchExpr); ok { @@ -1523,7 +1785,7 @@ func (b *blockWalker) checkStaticPropertyFetchNullSafety(expr *ir.StaticProperty return } - b.checkingPropertyFetchNullSafetyCondition(expr, propType, prp.Name, fn, paramIndex, haveVariadic) + b.checkingPropertyFetchSafetyCondition(expr, propType, prp.Name, fn, paramIndex, haveVariadic) } func (b *blockWalker) handleCallArgs(args []ir.Node, fn meta.FuncInfo) { diff --git a/src/solver/oop.go b/src/solver/oop.go index 5f6782c2..4ec767a4 100644 --- a/src/solver/oop.go +++ b/src/solver/oop.go @@ -60,6 +60,15 @@ func GetClassName(cs *meta.ClassParseState, classNode ir.Node) (className string className = nm.Value firstPart, restParts = nm.HeadTail() partsCount = nm.NumParts() + case *ir.SimpleVar: + varTyp, ok := cs.Info.GetVarType(nm) + + if !ok || varTyp.Len() > 1 { + return "", false + } + + return varTyp.String(), true + default: return "", false } diff --git a/src/tests/checkers/null_safety_test.go b/src/tests/checkers/null_safety_test.go index 14c40b1c..d3dce824 100644 --- a/src/tests/checkers/null_safety_test.go +++ b/src/tests/checkers/null_safety_test.go @@ -490,3 +490,37 @@ if ($user) { } test.RunAndMatch() } + +func TestPropertyFetchMiddleChainNullSafety(t *testing.T) { + test := linttest.NewSuite(t) + test.AddFile(`id = $id; + } +} + +class MyTask { + public ?ParentTask $parent_task; + + public function __construct(ParentTask $parent_task) { + $this->parent_task = $parent_task; + } + + public function execute(): void { + processTask($this->parent_task->id); + } +} + +function processTask(int $taskId): void { + echo "Processing task with ID: " . $taskId . "\n"; +} +`) + test.Expect = []string{ + "potential null dereference when accessing property 'parent_task'", + `Missing PHPDoc for \MyTask::execute public method`, + } + test.RunAndMatch() +} diff --git a/src/tests/golden/testdata/flysystem/golden.txt b/src/tests/golden/testdata/flysystem/golden.txt index 2268ef4c..dffa0afc 100644 --- a/src/tests/golden/testdata/flysystem/golden.txt +++ b/src/tests/golden/testdata/flysystem/golden.txt @@ -412,6 +412,12 @@ MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\Adapter\Polyfill\Str 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 ^ From cd3869ae677246b8f8d8a5b618c97f657457310c Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Thu, 10 Apr 2025 02:09:58 +0300 Subject: [PATCH 31/36] logic extern --- src/linter/block.go | 86 +++++++++++++++++++++++++++++++++------------ src/solver/oop.go | 21 +++++++---- 2 files changed, 79 insertions(+), 28 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index 2746463a..2358271d 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1064,11 +1064,11 @@ func (b *blockWalker) checkNotSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) case *ir.ListExpr: b.checkListExprSafety(arg, fn, i, a, haveVariadic) case *ir.PropertyFetchExpr: - b.checkPropertyFetchNotSafety(a, fn, i, haveVariadic) + b.checkUnifiedPropertyFetchNotSafety(a, fn, i, haveVariadic) case *ir.StaticCallExpr: b.checkStaticCallSafety(arg, fn, i, a, haveVariadic) case *ir.StaticPropertyFetchExpr: - b.checkStaticPropertyFetchNullSafety(a, fn, i, haveVariadic) + b.checkUnifiedPropertyFetchNotSafety(a, fn, i, haveVariadic) case *ir.FunctionCallExpr: b.checkFunctionCallSafety(arg, fn, i, a, haveVariadic) } @@ -1585,23 +1585,49 @@ func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.F finalPropType = propInfo.info.Typ finalPropName = ip.Value case *ir.StaticPropertyFetchExpr: - propInfo := resolveStaticPropertyFetch(globalMetaInfo, node) - if !propInfo.isFound { - return - } - sv, ok := node.Property.(*ir.SimpleVar) - if !ok { - return + variable, isVar := node.Property.(*ir.SimpleVar) + class, isClass := node.Class.(*ir.SimpleVar) + + if isVar && isClass { + if !isClass { + return + } + classTyp, ok := b.ctx.sc.GetVarType(class) + if !ok { + return + } + if classTyp.Contains("null") { + classTyp.Erase("null") + } + + property, found := solver.FindProperty(b.r.ctx.st.Info, classTyp.String(), "$"+variable.Name) + if !found { + return + } + + /* varTyp, ok := b.ctx.sc.GetVarType(variable) + if !ok { + return + } + varTyp = solver.MergeUnionTypes(b.r.metaInfo(), varTyp)*/ + + finalPropType = property.Info.Typ + finalPropName = variable.Name + } else { + propInfo := resolveStaticPropertyFetch(globalMetaInfo, node) + if !propInfo.isFound { + return + } + finalPropType = propInfo.info.Info.Typ + finalPropName = propInfo.propertyName } - finalPropType = propInfo.info.Info.Typ - finalPropName = sv.Name default: return } b.checkingPropertyFetchSafetyCondition(expr, finalPropType, finalPropName, fn, paramIndex, haveVariadic) - for i := 1; i < len(chain)-1; i++ { + for i := 1; i < len(chain); i++ { switch node := chain[i].(type) { case *ir.PropertyFetchExpr: propInfo := resolvePropertyFetch(b.ctx.sc, globalMetaInfo, b.ctx.customTypes, node, b.r.strictMixed) @@ -1614,26 +1640,42 @@ func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.F "potential null dereference when accessing property '%s'", propInfo.propertyNode.Value) return } - if propType.Len() > 1 || !propType.IsClass() { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing property '%s': intermediary node is not a class", propInfo.propertyNode.Value) - return - } + + propType.Iterate(func(typ string) { + if types.IsTrivial(typ) { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing property '%s': intermediary node is not a class", propInfo.propertyNode.Value) + return + } + }) + /* if propType.Len() > 1 || !propType.IsClass() { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing property '%s': intermediary node is not a class", propInfo.propertyNode.Value) + return + }*/ case *ir.SimpleVar: varType, ok := b.ctx.sc.GetVarType(node) if !ok { return } + varType = solver.MergeUnionTypes(b.r.metaInfo(), varType) if types.IsTypeNullable(varType) { b.report(node, LevelWarning, "notSafetyCall", "potential null dereference when accessing variable '%s'", node.Name) return } - if varType.Len() > 1 || !types.IsClass(varType.String()) { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing variable '%s': intermediary node is not a class", node.Name) - return - } + varType.Iterate(func(typ string) { + if types.IsTrivial(typ) { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing variable '%s': intermediary node is not a class", node.Name) + return + } + }) + /* if varType.Len() > 1 || !types.IsClass(varType.String()) { + b.report(node, LevelWarning, "notSafetyCall", + "potential not safety accessing variable '%s': intermediary node is not a class", node.Name) + return + }*/ } } } diff --git a/src/solver/oop.go b/src/solver/oop.go index 4ec767a4..765e0a7a 100644 --- a/src/solver/oop.go +++ b/src/solver/oop.go @@ -60,15 +60,24 @@ func GetClassName(cs *meta.ClassParseState, classNode ir.Node) (className string className = nm.Value firstPart, restParts = nm.HeadTail() partsCount = nm.NumParts() - case *ir.SimpleVar: - varTyp, ok := cs.Info.GetVarType(nm) - if !ok || varTyp.Len() > 1 { - return "", false - } + // TODO: here we have bug with data-race. uncomment it and run e2e phprocksyd + /* case *ir.SimpleVar: + varTyp, ok := cs.Info.GetVarType(nm) + varTyp = MergeUnionTypes(cs.Info, varTyp) + if varTyp.Contains("null") { + varTyp.Erase("null") + } + if !varTyp.IsClass() { + return "", false + } - return varTyp.String(), true + if !ok || varTyp.Len() > 1 || varTyp.Empty() { + return "", false + } + return varTyp.String(), true + */ default: return "", false } From 2d9eb7a3ebeb5ef9f7bed78a3d9a05a1eda37853 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Thu, 10 Apr 2025 02:10:59 +0300 Subject: [PATCH 32/36] refactoring --- src/linter/block.go | 253 +------------------------------------------- 1 file changed, 1 insertion(+), 252 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index 2358271d..ebf394bd 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1400,91 +1400,6 @@ func (b *blockWalker) checkListExprSafety(arg ir.Node, fn meta.FuncInfo, paramIn } } -func (b *blockWalker) getPropertyComputedType(expr ir.Node) (meta.ClassInfo, types.Map) { - var baseNode ir.Node - var propertyNode ir.Node - - switch e := expr.(type) { - case *ir.PropertyFetchExpr: - baseNode = e.Variable - propertyNode = e.Property - case *ir.StaticPropertyFetchExpr: - baseNode = e.Class - propertyNode = e.Property - default: - return meta.ClassInfo{}, types.Map{} - } - - var classInfo meta.ClassInfo - var ok bool - var varType string - - if baseCall, ok := baseNode.(*ir.SimpleVar); ok { - varInfo, found := b.ctx.sc.GetVar(baseCall) - if !found { - return meta.ClassInfo{}, types.Map{} - } - varType = varInfo.Type.String() - } else if nameNode, ok := baseNode.(*ir.Name); ok { - varType = "\\" + nameNode.Value - } else { - return meta.ClassInfo{}, types.Map{} - } - - classInfo, ok = b.r.ctx.st.Info.GetClass(varType) - if !ok { - return meta.ClassInfo{}, types.Map{} - } - - switch prop := propertyNode.(type) { - case *ir.Identifier: - propertyInfoFromClass := classInfo.Properties[prop.Value] - return classInfo, propertyInfoFromClass.Typ - case *ir.SimpleVar: - // static: $maybeClass::$value - propertyInfoFromClass := classInfo.Properties["$"+prop.Name] - return classInfo, propertyInfoFromClass.Typ - default: - return meta.ClassInfo{}, types.Map{} - } -} - -func (b *blockWalker) checkPropertyIntermediaryNodeSafety(node *ir.PropertyFetchExpr, propType types.Map, propName string) { - if types.IsTypeNullable(propType) { - b.report(node, LevelWarning, "notNullSafetyFunctionArgumentPropertyFetch", - "potential null dereference when accessing property '%s'", propName) - return - } - if propType.Len() > 1 { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing property '%s': intermediary node is not a class", propName) - return - } - if !propType.IsClass() { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing property '%s': intermediary node is not a class", propName) - return - } -} - -func (b *blockWalker) checkPropertyIntermediaryVariableSafety(node *ir.SimpleVar, varType types.Map, varName string) { - if types.IsTypeNullable(varType) { - b.report(node, LevelWarning, "notNullSafetyFunctionArgumentPropertyFetch", - "potential null dereference when accessing property '%s'", varName) - return - } - if varType.Len() > 1 { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing property '%s': intermediary node is not a class", varName) - return - } - if !types.IsClass(varType.String()) { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing property '%s': intermediary node is not a class", varName) - return - } -} - // checkingPropertyFetchSafetyCondition verifies the safety of the final property fetch // (the rightmost node in the chain) by checking null-safety and type compatibility func (b *blockWalker) checkingPropertyFetchSafetyCondition( @@ -1561,7 +1476,6 @@ func (b *blockWalker) collectUnifiedPropertyFetchChain(expr ir.Node) []ir.Node { // checkUnifiedPropertyFetchNotSafety combines checks for instance and static property access // For the final (rightmost) node (the one being substituted), we check null and type safety // and all intermediate nodes (except the base one) must be classes -// TODO: THIS IS MAIN!!! func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { chain := b.collectUnifiedPropertyFetchChain(expr) if len(chain) == 0 { @@ -1605,12 +1519,6 @@ func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.F return } - /* varTyp, ok := b.ctx.sc.GetVarType(variable) - if !ok { - return - } - varTyp = solver.MergeUnionTypes(b.r.metaInfo(), varTyp)*/ - finalPropType = property.Info.Typ finalPropName = variable.Name } else { @@ -1618,6 +1526,7 @@ func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.F if !propInfo.isFound { return } + finalPropType = propInfo.info.Info.Typ finalPropName = propInfo.propertyName } @@ -1648,11 +1557,6 @@ func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.F return } }) - /* if propType.Len() > 1 || !propType.IsClass() { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing property '%s': intermediary node is not a class", propInfo.propertyNode.Value) - return - }*/ case *ir.SimpleVar: varType, ok := b.ctx.sc.GetVarType(node) if !ok { @@ -1671,165 +1575,10 @@ func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.F return } }) - /* if varType.Len() > 1 || !types.IsClass(varType.String()) { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing variable '%s': intermediary node is not a class", node.Name) - return - }*/ } } } -// TODO: only for test racing -func (b *blockWalker) checkPropertyFetchNotSafety(expr *ir.PropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { - chain := b.collectUnifiedPropertyFetchChain(expr) - if len(chain) == 0 { - return - } - - globalMetaInfo := b.linter.classParseState() - - // --- Process final (rightmost) node (expected to be instance property fetch) - node, ok := chain[0].(*ir.PropertyFetchExpr) - if !ok { - return - } - propInfo := resolvePropertyFetch(b.ctx.sc, globalMetaInfo, b.ctx.customTypes, node, b.r.strictMixed) - if !propInfo.isFound { - return - } - ip, ok := node.Property.(*ir.Identifier) - if !ok { - return - } - finalPropType := propInfo.info.Typ - finalPropName := ip.Value - - b.checkingPropertyFetchSafetyCondition(expr, finalPropType, finalPropName, fn, paramIndex, haveVariadic) - - // --- Process intermediate nodes (excluding the base node) - for i := 1; i < len(chain)-1; i++ { - switch node := chain[i].(type) { - case *ir.PropertyFetchExpr: - propInfo := resolvePropertyFetch(b.ctx.sc, globalMetaInfo, b.ctx.customTypes, node, b.r.strictMixed) - if !propInfo.isFound { - return - } - propType := propInfo.info.Typ - if types.IsTypeNullable(propType) { - b.report(node, LevelWarning, "notSafetyCall", - "potential null dereference when accessing property '%s'", propInfo.propertyNode.Value) - return - } - if propType.Len() > 1 || !propType.IsClass() { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing property '%s': intermediary node is not a class", propInfo.propertyNode.Value) - return - } - case *ir.SimpleVar: - varType, ok := b.ctx.sc.GetVarType(node) - if !ok { - return - } - if types.IsTypeNullable(varType) { - b.report(node, LevelWarning, "notSafetyCall", - "potential null dereference when accessing variable '%s'", node.Name) - return - } - if varType.Len() > 1 || !types.IsClass(varType.String()) { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing variable '%s': intermediary node is not a class", node.Name) - return - } - } - } -} - -// TODO: only for test racing -func (b *blockWalker) checkStaticPropertyFetchNotSafety(expr *ir.StaticPropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { - chain := b.collectUnifiedPropertyFetchChain(expr) - if len(chain) == 0 { - return - } - - globalMetaInfo := b.linter.classParseState() - - // --- Process final (rightmost) node (expected to be static property fetch) - node, ok := chain[0].(*ir.StaticPropertyFetchExpr) - if !ok { - return - } - propInfo := resolveStaticPropertyFetch(globalMetaInfo, node) - if !propInfo.isFound { - return - } - sv, ok := node.Property.(*ir.SimpleVar) - if !ok { - return - } - finalPropType := propInfo.info.Info.Typ - finalPropName := sv.Name - - b.checkingPropertyFetchSafetyCondition(expr, finalPropType, finalPropName, fn, paramIndex, haveVariadic) - - // --- Process intermediate nodes (excluding the base node) - for i := 1; i < len(chain)-1; i++ { - switch node := chain[i].(type) { - case *ir.StaticPropertyFetchExpr: - propInfo := resolveStaticPropertyFetch(globalMetaInfo, node) - if !propInfo.isFound { - return - } - propType := propInfo.info.Info.Typ - if types.IsTypeNullable(propType) { - b.report(node, LevelWarning, "notSafetyCall", - "potential null dereference when accessing static property '%s'", propInfo.propertyName) - return - } - if propType.Len() > 1 || !propType.IsClass() { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing static property '%s': intermediary node is not a class", propInfo.propertyName) - return - } - case *ir.SimpleVar: - varType, ok := b.ctx.sc.GetVarType(node) - if !ok { - return - } - if types.IsTypeNullable(varType) { - b.report(node, LevelWarning, "notSafetyCall", - "potential null dereference when accessing variable '%s'", node.Name) - return - } - if varType.Len() > 1 || !types.IsClass(varType.String()) { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing variable '%s': intermediary node is not a class", node.Name) - return - } - } - } -} - -// TODO: old variant -func (b *blockWalker) checkStaticPropertyFetchNullSafety(expr *ir.StaticPropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) { - // Recursively check the left part of the chain if it is also a property fetch. - if nested, ok := expr.Class.(*ir.StaticPropertyFetchExpr); ok { - b.checkStaticPropertyFetchNullSafety(nested, fn, paramIndex, haveVariadic) - } - - classInfo, propType := b.getPropertyComputedType(expr) - if classInfo.Name == "" || propType.Empty() { - return - } - - prp, ok := expr.Property.(*ir.SimpleVar) - if !ok { - return - } - - b.checkingPropertyFetchSafetyCondition(expr, propType, prp.Name, fn, paramIndex, haveVariadic) -} - func (b *blockWalker) handleCallArgs(args []ir.Node, fn meta.FuncInfo) { b.checkNotSafetyCallArgsF(args, fn) From 4b363da6453820215ec7b9234f839c01e0673ffe Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Thu, 10 Apr 2025 04:11:56 +0300 Subject: [PATCH 33/36] closure & callable --- src/linter/block.go | 4 ++++ src/tests/golden/testdata/flysystem/golden.txt | 12 ------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/linter/block.go b/src/linter/block.go index ebf394bd..583ccfca 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1244,6 +1244,7 @@ func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) b isVarBoolean := forcedVarType.IsBoolean() isClass := forcedVarType.IsClass() varClassName := forcedVarType.String() + isClosure := types.IsClosure(forcedVarType.String()) for _, param := range paramType.Keys() { // boolean case @@ -1278,6 +1279,9 @@ func (b *blockWalker) isTypeCompatible(varType types.Map, paramType types.Map) b forcedParamType := types.NewMapFromMap(solver.ResolveTypes(b.r.metaInfo(), "", paramType, solver.ResolverMap{})) + if isClosure && forcedParamType.Contains("callable") { + return true + } // TODO: This is bullshit because we have no good type inferring for arrays: bool[1] will be bool[]! !not bool! if strings.Contains(forcedParamType.String(), "[") { idx := strings.Index(forcedParamType.String(), "[") diff --git a/src/tests/golden/testdata/flysystem/golden.txt b/src/tests/golden/testdata/flysystem/golden.txt index dffa0afc..a14094d1 100644 --- a/src/tests/golden/testdata/flysystem/golden.txt +++ b/src/tests/golden/testdata/flysystem/golden.txt @@ -13,9 +13,6 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string2 of function strnatcmp at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:379 return strnatcmp($one['path'], $two['path']); ^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function usort signature of param callback at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:382 - usort($result, $compare); - ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function forFtpSystemType signature of param systemType at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:407 throw NotSupportedException::forFtpSystemType($systemType); ^^^^^^^^^^^ @@ -43,15 +40,9 @@ WARNING notSafetyCall: potential not safety call in function strtr signature of WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function str_split signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:576 return array_sum(str_split($part)); ^^^^^ -WARNING notSafetyCall: potential not safety call in function array_map signature of param callback at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:580 - return octdec(implode('', array_map($mapper, $parts))); - ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:593 return $line !== '' && ! preg_match('#.* \.(\.)?$|^total#', $line); ^^^^^ -WARNING notSafetyCall: potential not safety call in function array_filter signature of param callback at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:596 - return array_filter($list, $filter); - ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function getMetadata signature of param path at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:604 return $this->getMetadata($path); ^^^^^ @@ -517,9 +508,6 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ucfirst signature of param string at testdata/flysystem/src/Plugin/GetWithMetadata.php:42 if ( ! method_exists($this->filesystem, $method = 'get' . ucfirst($key))) { ^^^^ -WARNING notSafetyCall: potential not safety call in function array_filter signature of param callback at testdata/flysystem/src/Plugin/ListFiles.php:33 - return array_values(array_filter($contents, $filter)); - ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/flysystem/src/Plugin/PluggableTrait.php:72 return call_user_func_array($callback, $arguments); ^^^^^^^^^ From 41dcb5614918210c9af9ed41659e323f55652349 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Mon, 14 Apr 2025 18:21:20 +0300 Subject: [PATCH 34/36] grammar fix --- docs/checkers_doc.md | 20 ++--- src/linter/block.go | 48 +++++----- src/linter/block_linter.go | 8 +- src/linter/report.go | 26 +++--- src/tests/checkers/not_safety_test.go | 36 ++++---- src/tests/golden/testdata/ctype/golden.txt | 24 ++--- .../golden/testdata/embeddedrules/golden.txt | 32 +++---- .../golden/testdata/flysystem/golden.txt | 90 +++++++++---------- src/tests/golden/testdata/idn/golden.txt | 12 +-- src/tests/golden/testdata/math/golden.txt | 42 ++++----- src/tests/golden/testdata/mustache/golden.txt | 50 +++++------ .../testdata/options-resolver/golden.txt | 22 ++--- .../golden/testdata/parsedown/golden.txt | 54 +++++------ .../golden/testdata/phprocksyd/golden.txt | 48 +++++----- src/tests/golden/testdata/qrcode/golden.txt | 56 ++++++------ .../testdata/twitter-api-php/golden.txt | 24 ++--- .../golden/testdata/underscore/golden.txt | 58 ++++++------ 17 files changed, 325 insertions(+), 325 deletions(-) diff --git a/docs/checkers_doc.md b/docs/checkers_doc.md index 5d7b1690..1c28d347 100644 --- a/docs/checkers_doc.md +++ b/docs/checkers_doc.md @@ -1252,7 +1252,7 @@ test($arr[1]); #### Compliant code: ```php -reported not safety call +reported not safe call call ```


@@ -1303,7 +1303,7 @@ test(testNullable()); #### Compliant code: ```php -reported not safety call +reported not safe call call ```


@@ -1321,7 +1321,7 @@ test(list($a) = [null]); #### Compliant code: ```php -reported not safety call +reported not safe call call ```


@@ -1346,7 +1346,7 @@ echo $user->name; #### Compliant code: ```php -reported not safety call +reported not safe call call ```


@@ -1374,7 +1374,7 @@ test(A::hello()); #### Compliant code: ```php -reported not safety call +reported not safe call call ```


@@ -1393,7 +1393,7 @@ function f(A $klass); #### Compliant code: ```php -reported not safety call with null in variable. +reported not safe call call with null in variable. ```


@@ -1413,7 +1413,7 @@ $getUserOrNull()->test(); #### Compliant code: ```php -reported not safety function call +reported not safe call function call ```


@@ -1438,7 +1438,7 @@ echo $user->name; #### Compliant code: ```php -reported not safety call +reported not safe call call ```


@@ -1466,7 +1466,7 @@ test(A::hello()); #### Compliant code: ```php -reported not safety static function call +reported not safe call static function call ```


@@ -1488,7 +1488,7 @@ echo $user->name; #### Compliant code: ```php -reported not safety call with null in variable. +reported not safe call call with null in variable. ```


diff --git a/src/linter/block.go b/src/linter/block.go index 583ccfca..ec2c899d 100644 --- a/src/linter/block.go +++ b/src/linter/block.go @@ -1038,7 +1038,7 @@ func formatSlashesFuncName(fn meta.FuncInfo) string { return strings.TrimPrefix(fn.Name, "\\") } -func (b *blockWalker) checkNotSafetyCallArgsF(args []ir.Node, fn meta.FuncInfo) { +func (b *blockWalker) checknotSafeCallArgsF(args []ir.Node, fn meta.FuncInfo) { if fn.Params == nil || fn.Name == "" { return } @@ -1125,8 +1125,8 @@ func (b *blockWalker) checkFunctionCallSafety(arg ir.Node, fn meta.FuncInfo, par } if !b.isTypeCompatible(callType, param.Typ) { - b.report(arg, LevelWarning, "notSafetyCall", - "potential not safety call in function %s signature of param %s when calling function %s", + b.report(arg, LevelWarning, "notSafeCall", + "potentially not safe call in function %s signature of param %s when calling function %s", formatSlashesFuncName(fn), param.Name, funcInfo.Name) } } @@ -1181,8 +1181,8 @@ func (b *blockWalker) checkStaticCallSafety(arg ir.Node, fn meta.FuncInfo, param } if !b.isTypeCompatible(funcType, param.Typ) { - b.report(arg, LevelWarning, "notSafetyCall", - "potential not safety static call in function %s signature of param %s", + b.report(arg, LevelWarning, "notSafeCall", + "potentially not safe static call in function %s signature of param %s", formatSlashesFuncName(fn), param.Name) } } @@ -1215,8 +1215,8 @@ func (b *blockWalker) checkSimpleVarSafety(arg ir.Node, fn meta.FuncInfo, paramI } if !b.isTypeCompatible(varType, paramType) { - b.report(arg, LevelWarning, "notSafetyCall", - "potential not safety call in function %s signature of param %s", + b.report(arg, LevelWarning, "notSafeCall", + "potentially not safe call in function %s signature of param %s", formatSlashesFuncName(fn), param.Name) } } @@ -1318,8 +1318,8 @@ func (b *blockWalker) checkConstFetchSafety(arg ir.Node, fn meta.FuncInfo, param if isBool { typ := types.NewMap(constVal) if !b.isTypeCompatible(typ, paramType) { - b.report(arg, LevelWarning, "notSafetyCall", - "potential not safety access in parameter %s of function %s", + b.report(arg, LevelWarning, "notSafeCall", + "potentially not safe access in parameter %s of function %s", param.Name, formatSlashesFuncName(fn)) } } @@ -1357,8 +1357,8 @@ func (b *blockWalker) checkArrayDimFetchSafety(arg ir.Node, fn meta.FuncInfo, pa } if !b.isTypeCompatible(varType, param.Typ) { - b.report(arg, LevelWarning, "notSafetyCall", - "potential not safety array access in parameter %s of function %s", + b.report(arg, LevelWarning, "notSafeCall", + "potentially not safe array access in parameter %s of function %s", param.Name, formatSlashesFuncName(fn)) } } @@ -1370,7 +1370,7 @@ func (b *blockWalker) checkListExprSafety(arg ir.Node, fn meta.FuncInfo, paramIn } if item.Key != nil { - b.checkNotSafetyCallArgsF([]ir.Node{item.Key}, fn) + b.checknotSafeCallArgsF([]ir.Node{item.Key}, fn) } if item.Val != nil { @@ -1393,13 +1393,13 @@ func (b *blockWalker) checkListExprSafety(arg ir.Node, fn meta.FuncInfo, paramIn } if !b.isTypeCompatible(varType, paramType) { - b.report(arg, LevelWarning, "notSafetyCall", - "potential not safety list assignment for param %s in function %s", + b.report(arg, LevelWarning, "notSafeCall", + "potentially not safe list assignment for param %s in function %s", param.Name, formatSlashesFuncName(fn)) } } } - b.checkNotSafetyCallArgsF([]ir.Node{item.Val}, fn) + b.checknotSafeCallArgsF([]ir.Node{item.Val}, fn) } } } @@ -1441,8 +1441,8 @@ func (b *blockWalker) checkingPropertyFetchSafetyCondition( } if !b.isTypeCompatible(propType, paramType) { - b.report(expr, LevelWarning, "notSafetyCall", - "potential not safety accessing property '%s'", prpName) + b.report(expr, LevelWarning, "notSafeCall", + "potentially not safe accessing property '%s'", prpName) } } @@ -1549,15 +1549,15 @@ func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.F } propType := propInfo.info.Typ if types.IsTypeNullable(propType) { - b.report(node, LevelWarning, "notSafetyCall", + b.report(node, LevelWarning, "notSafeCall", "potential null dereference when accessing property '%s'", propInfo.propertyNode.Value) return } propType.Iterate(func(typ string) { if types.IsTrivial(typ) { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing property '%s': intermediary node is not a class", propInfo.propertyNode.Value) + b.report(node, LevelWarning, "notSafeCall", + "potentially not safe accessing property '%s': intermediary node is not a class", propInfo.propertyNode.Value) return } }) @@ -1568,14 +1568,14 @@ func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.F } varType = solver.MergeUnionTypes(b.r.metaInfo(), varType) if types.IsTypeNullable(varType) { - b.report(node, LevelWarning, "notSafetyCall", + b.report(node, LevelWarning, "notSafeCall", "potential null dereference when accessing variable '%s'", node.Name) return } varType.Iterate(func(typ string) { if types.IsTrivial(typ) { - b.report(node, LevelWarning, "notSafetyCall", - "potential not safety accessing variable '%s': intermediary node is not a class", node.Name) + b.report(node, LevelWarning, "notSafeCall", + "potentially not safe accessing variable '%s': intermediary node is not a class", node.Name) return } }) @@ -1584,7 +1584,7 @@ func (b *blockWalker) checkUnifiedPropertyFetchNotSafety(expr ir.Node, fn meta.F } func (b *blockWalker) handleCallArgs(args []ir.Node, fn meta.FuncInfo) { - b.checkNotSafetyCallArgsF(args, fn) + b.checknotSafeCallArgsF(args, fn) for i, arg := range args { if i >= len(fn.Params) { diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 9f25b8b9..66cd5c13 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -1422,12 +1422,12 @@ func (b *blockLinter) checkSafetyCall(e ir.Node, typ types.Map, name string, suf if !isSafetyCall { if name == "" { - b.report(e, LevelWarning, "notSafetyCall", - "potential not safety call when accessing property") + b.report(e, LevelWarning, "notSafeCall", + "potentially not safe call when accessing property") return } - b.report(e, LevelWarning, "notSafetyCall", - "potential not safety call in %s when accessing method", name) + b.report(e, LevelWarning, "notSafeCall", + "potentially not safe call in %s when accessing method", name) } } diff --git a/src/linter/report.go b/src/linter/report.go index f3d0cc91..c4c9c62f 100644 --- a/src/linter/report.go +++ b/src/linter/report.go @@ -26,10 +26,10 @@ func addBuiltinCheckers(reg *CheckersRegistry) { }, { - Name: "notSafetyCall", + Name: "notSafeCall", Default: true, Quickfix: false, - Comment: "Report not safety call", + Comment: "Report not safe call call", Before: `/** * @return User|false */ @@ -38,7 +38,7 @@ function getUser():User|false { } $a = getUser()->do(); `, - After: `reported not safety call`, + After: `reported not safe call`, }, { @@ -47,7 +47,7 @@ $a = getUser()->do(); Quickfix: false, Comment: "Report not nullsafety call for null list", Before: `test(list($a) = [null]);`, - After: `reported not safety call`, + After: `reported not safe call call`, }, { @@ -65,7 +65,7 @@ function test(A $a): void { $arr = [new A(), null]; test($arr[1]);`, - After: `reported not safety call`, + After: `reported not safe call call`, }, { @@ -94,7 +94,7 @@ function test(string $s): void { } test(A::hello());`, - After: `reported not safety call`, + After: `reported not safe call call`, }, { @@ -104,7 +104,7 @@ test(A::hello());`, Comment: "Report not nullsafety call", Before: `function f(A $klass); f(null);`, - After: `reported not safety call with null in variable.`, + After: `reported not safe call call with null in variable.`, }, { @@ -127,7 +127,7 @@ function testNullable(): ?A{ } test(testNullable());`, - After: `reported not safety call`, + After: `reported not safe call call`, }, { @@ -143,7 +143,7 @@ class User { $user = new User(); $user = null; echo $user->name;`, - After: `reported not safety call`, + After: `reported not safe call call`, }, { @@ -159,7 +159,7 @@ class User { $user = new User(); $user = null; echo $user->name;`, - After: `reported not safety call`, + After: `reported not safe call call`, }, { @@ -172,7 +172,7 @@ echo $user->name;`, $user = null; echo $user->name;`, - After: `reported not safety call with null in variable.`, + After: `reported not safe call call with null in variable.`, }, { @@ -183,7 +183,7 @@ echo $user->name;`, Before: `function getUserOrNull(): ?User { echo "test"; } $getUserOrNull()->test();`, - After: `reported not safety function call`, + After: `reported not safe call function call`, }, { @@ -202,7 +202,7 @@ function test(string $s): void { } test(A::hello());`, - After: `reported not safety static function call`, + After: `reported not safe call static function call`, }, { diff --git a/src/tests/checkers/not_safety_test.go b/src/tests/checkers/not_safety_test.go index 3aa69fb7..8135dade 100644 --- a/src/tests/checkers/not_safety_test.go +++ b/src/tests/checkers/not_safety_test.go @@ -16,7 +16,7 @@ $var = false; test($var); `) test.Expect = []string{ - "not safety call in function test signature of param", + "potentially not safe call in function test signature of param", } test.RunAndMatch() } @@ -30,7 +30,7 @@ function test(string $s): void { test(false); `) test.Expect = []string{ - "potential not safety access in parameter s of function test", + "potentially not safe access in parameter s of function test", } test.RunAndMatch() } @@ -62,7 +62,7 @@ $arr = [false]; test($arr[0]); `) test.Expect = []string{ - "not safety array access in parameter s of function test", + "potentially not safe array access in parameter s of function test", } test.RunAndMatch() } @@ -91,7 +91,7 @@ list($a) = [false]; test($a); `) test.Expect = []string{ - "not safety call in function test signature of param s", + "potentially not safe call in function test signature of param s", } test.RunAndMatch() } @@ -108,7 +108,7 @@ function test(string $s): void { test(C::$value); `) test.Expect = []string{ - "potential not safety accessing property 'value'", + "potentially not safe accessing property 'value'", } test.RunAndMatch() } @@ -125,7 +125,7 @@ function test(string $s): void { test(getValue()); `) test.Expect = []string{ - "not safety call in function test signature of param s when calling function \\getValue", + "potentially not safe call in function test signature of param s when calling function \\getValue", } test.RunAndMatch() } @@ -185,7 +185,7 @@ $с = $b->do(); test.Expect = []string{ "Missing PHPDoc for \\User::do public method", "Call to undefined method", - "potential not safety call in b when accessing method", + "potentially not safe call in b when accessing method", } test.RunAndMatch() } @@ -211,7 +211,7 @@ $a = getUser()->do(); `) test.Expect = []string{ "Missing PHPDoc for \\User::do public method", - "potential not safety call in \\getUser when accessing method", + "potentially not safe call in \\getUser when accessing method", } test.RunAndMatch() } @@ -225,7 +225,7 @@ function testValue(string $value): void { testValue(false); `) test.Expect = []string{ - "potential not safety access in parameter value of function testValue", + "potentially not safe access in parameter value of function testValue", } test.RunAndMatch() } @@ -247,7 +247,7 @@ test(A::hello()); `) test.Expect = []string{ "Missing PHPDoc for \\A::hello public method", - "not safety static call in function test signature of param s", + "potentially not safe static call in function test signature of param s", } test.RunAndMatch() } @@ -268,7 +268,7 @@ testValue(falseFunc()); } `) test.Expect = []string{ - "not safety call in function testValue signature of param value when calling function \\falseFunc", + "potentially not safe call in function testValue signature of param value when calling function \\falseFunc", "Unreachable code", } test.RunAndMatch() @@ -292,7 +292,7 @@ $a = new A(); test($a->b); `) test.Expect = []string{ - "potential not safety accessing property 'b'", + "potentially not safe accessing property 'b'", } test.RunAndMatch() } @@ -317,7 +317,7 @@ $b = $x->name; `) test.Expect = []string{ "Property {int}->name does not exist", - "potential not safety call when accessing property", + "potentially not safe call when accessing property", } test.RunAndMatch() } @@ -342,7 +342,7 @@ $b = $x->name; `) test.Expect = []string{ "Property {int}->name does not exist", - "potential not safety call when accessing property", + "potentially not safe call when accessing property", } test.RunAndMatch() } @@ -452,9 +452,9 @@ if ($user) { } `) test.Expect = []string{ - "potential not safety call when accessing property", + "potentially not safe call when accessing property", "Property {false}->name does not exist", - "potential not safety call when accessing property", + "potentially not safe call when accessing property", } test.RunAndMatch() } @@ -480,9 +480,9 @@ if (!$user) { } `) test.Expect = []string{ - "potential not safety call when accessing property", + "potentially not safe call when accessing property", "Property {false}->name does not exist", - "potential not safety call when accessing property", + "potentially not safe call when accessing property", } test.RunAndMatch() } diff --git a/src/tests/golden/testdata/ctype/golden.txt b/src/tests/golden/testdata/ctype/golden.txt index df4b4157..13274269 100644 --- a/src/tests/golden/testdata/ctype/golden.txt +++ b/src/tests/golden/testdata/ctype/golden.txt @@ -1,34 +1,34 @@ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:36 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:36 return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text); ^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:52 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:52 return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text); ^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:68 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:68 return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text); ^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:84 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:84 return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text); ^^^^^ MAYBE regexpSimplify: May re-write '/[^0-9]/' as '/\D/' at testdata/ctype/ctype.php:84 return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text); ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:100 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:100 return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text); ^^^^^ WARNING regexpVet: suspicious char range '!-~' in [^!-~] at testdata/ctype/ctype.php:100 return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text); ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:116 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:116 return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text); ^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:132 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:132 return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text); ^^^^^ WARNING regexpVet: suspicious char range ' -~' in [^ -~] at testdata/ctype/ctype.php:132 return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text); ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:148 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:148 return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); ^^^^^ MAYBE regexpSimplify: May re-write '/[^!-\/\:-@\[-`\{-~]/' as '/[^!-\/:-@\[-`\{-~]/' at testdata/ctype/ctype.php:148 @@ -37,18 +37,18 @@ MAYBE regexpSimplify: May re-write '/[^!-\/\:-@\[-`\{-~]/' as '/[^!-\/:-@\[-`\ WARNING regexpVet: suspicious char range '!-\/' in [^!-\/\:-@\[-`\{-~] at testdata/ctype/ctype.php:148 return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:164 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:164 return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text); ^^^^^ MAYBE regexpSimplify: May re-write '/[^\s]/' as '/\S/' at testdata/ctype/ctype.php:164 return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text); ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:180 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:180 return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text); ^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/ctype/ctype.php:196 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/ctype/ctype.php:196 return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text); ^^^^^ -WARNING notSafetyCall: potential not safety call in function chr signature of param codepoint at testdata/ctype/ctype.php:225 +WARNING notSafeCall: potentially not safe call in function chr signature of param codepoint at testdata/ctype/ctype.php:225 return \chr($int); ^^^^ diff --git a/src/tests/golden/testdata/embeddedrules/golden.txt b/src/tests/golden/testdata/embeddedrules/golden.txt index fb4df175..ea5cbcd8 100644 --- a/src/tests/golden/testdata/embeddedrules/golden.txt +++ b/src/tests/golden/testdata/embeddedrules/golden.txt @@ -109,97 +109,97 @@ $_ = $b[0]{0}; WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:21 $_ = strpos($str, 10); ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strpos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:22 +WARNING notSafeCall: potentially not safe call in function strpos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:22 $_ = strpos($str, getInt()); ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:22 $_ = strpos($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strpos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:23 +WARNING notSafeCall: potentially not safe call in function strpos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:23 $_ = strpos($str, getIntOrString(true)); // ok ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:27 $_ = strrpos($str, 10); ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strrpos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:28 +WARNING notSafeCall: potentially not safe call in function strrpos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:28 $_ = strrpos($str, getInt()); ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:28 $_ = strrpos($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strrpos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:29 +WARNING notSafeCall: potentially not safe call in function strrpos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:29 $_ = strrpos($str, getIntOrString(true)); // ok ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:33 $_ = stripos($str, 10); ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stripos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:34 +WARNING notSafeCall: potentially not safe call in function stripos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:34 $_ = stripos($str, getInt()); ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:34 $_ = stripos($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stripos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:35 +WARNING notSafeCall: potentially not safe call in function stripos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:35 $_ = stripos($str, getIntOrString(true)); // ok ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:39 $_ = strripos($str, 10); ^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strripos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:40 +WARNING notSafeCall: potentially not safe call in function strripos signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:40 $_ = strripos($str, getInt()); ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:40 $_ = strripos($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strripos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:41 +WARNING notSafeCall: potentially not safe call in function strripos signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:41 $_ = strripos($str, getIntOrString(true)); // ok ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:45 $_ = strstr($str, 10); ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strstr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:46 +WARNING notSafeCall: potentially not safe call in function strstr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:46 $_ = strstr($str, getInt()); ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:46 $_ = strstr($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strstr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:47 +WARNING notSafeCall: potentially not safe call in function strstr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:47 $_ = strstr($str, getIntOrString(true)); // ok ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:51 $_ = strchr($str, 10); ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strchr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:52 +WARNING notSafeCall: potentially not safe call in function strchr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:52 $_ = strchr($str, getInt()); ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:52 $_ = strchr($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strchr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:53 +WARNING notSafeCall: potentially not safe call in function strchr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:53 $_ = strchr($str, getIntOrString(true)); // ok ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:57 $_ = strrchr($str, 10); ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strrchr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:58 +WARNING notSafeCall: potentially not safe call in function strrchr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:58 $_ = strrchr($str, getInt()); ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:58 $_ = strrchr($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strrchr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:59 +WARNING notSafeCall: potentially not safe call in function strrchr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:59 $_ = strrchr($str, getIntOrString(true)); // ok ^^^^^^^^^^^^^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:63 $_ = stristr($str, 10); ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stristr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:64 +WARNING notSafeCall: potentially not safe call in function stristr signature of param needle when calling function \getInt at testdata/embeddedrules/intNeedle.php:64 $_ = stristr($str, getInt()); ^^^^^^^^ WARNING intNeedle: Since PHP 7.3, passing the int parameter needle to string search functions has been deprecated, cast it explicitly to string or wrap it in a chr() function call at testdata/embeddedrules/intNeedle.php:64 $_ = stristr($str, getInt()); ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stristr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:65 +WARNING notSafeCall: potentially not safe call in function stristr signature of param needle when calling function \getIntOrString at testdata/embeddedrules/intNeedle.php:65 $_ = stristr($str, getIntOrString(true)); // ok ^^^^^^^^^^^^^^^^^^^^ WARNING langDeprecated: Since PHP 7.3, the definition of case insensitive constants has been deprecated at testdata/embeddedrules/langDeprecated.php:3 diff --git a/src/tests/golden/testdata/flysystem/golden.txt b/src/tests/golden/testdata/flysystem/golden.txt index a14094d1..7ca6977a 100644 --- a/src/tests/golden/testdata/flysystem/golden.txt +++ b/src/tests/golden/testdata/flysystem/golden.txt @@ -1,4 +1,4 @@ -WARNING notSafetyCall: potential not safety call in function ucfirst signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:111 +WARNING notSafeCall: potentially not safe call in function ucfirst signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:111 $method = 'set' . ucfirst($setting); ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:358 @@ -34,7 +34,7 @@ MAYBE regexpSimplify: May re-write '/^[0-9]{2,4}-[0-9]{2}-[0-9]{2}/' as '/^\d{ MAYBE callSimplify: Could simplify to $permissions[0] at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:548 return substr($permissions, 0, 1) === 'd' ? 'dir' : 'file'; ^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strtr signature of param str at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:569 +WARNING notSafeCall: potentially not safe call in function strtr signature of param str at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:569 $permissions = strtr($permissions, $map); ^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function str_split signature of param string at testdata/flysystem/src/Adapter/AbstractFtpAdapter.php:576 @@ -67,10 +67,10 @@ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference w WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:176 if ( ! ftp_pasv($this->connection, $this->passive)) { ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ftp_chdir signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:191 +WARNING notSafeCall: potentially not safe call in function ftp_chdir signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:191 if ($root && ! ftp_chdir($connection, $root)) { ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ftp_pwd signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:199 +WARNING notSafeCall: potentially not safe call in function ftp_pwd signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:199 $this->root = ftp_pwd($connection); ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:212 @@ -82,16 +82,16 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:233 @ftp_close($this->connection); ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function fwrite signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:245 +WARNING notSafeCall: potentially not safe call in function fwrite signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:245 fwrite($stream, $contents); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function fwrite signature of param data at testdata/flysystem/src/Adapter/Ftp.php:245 fwrite($stream, $contents); ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function rewind signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:246 +WARNING notSafeCall: potentially not safe call in function rewind signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:246 rewind($stream); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function fclose signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:248 +WARNING notSafeCall: potentially not safe call in function fclose signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:248 fclose($stream); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function guessMimeType signature of param path at testdata/flysystem/src/Adapter/Ftp.php:255 @@ -124,13 +124,13 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function listDirectoryContents signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:318 $contents = array_reverse($this->listDirectoryContents($dirname, false)); ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ftp_delete signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:322 +WARNING notSafeCall: potentially not safe call in function ftp_delete signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:322 if ( ! ftp_delete($connection, $object['path'])) { ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter filename of function ftp_delete at testdata/flysystem/src/Adapter/Ftp.php:322 if ( ! ftp_delete($connection, $object['path'])) { ^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ftp_rmdir signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:330 +WARNING notSafeCall: potentially not safe call in function ftp_rmdir signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:330 return ftp_rmdir($connection, $dirname); ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_rmdir signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:330 @@ -139,10 +139,10 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function explode signature of param string at testdata/flysystem/src/Adapter/Ftp.php:339 $directories = explode('/', $dirname); ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function createActualDirectory signature of param connection at testdata/flysystem/src/Adapter/Ftp.php:342 +WARNING notSafeCall: potentially not safe call in function createActualDirectory signature of param connection at testdata/flysystem/src/Adapter/Ftp.php:342 if (false === $this->createActualDirectory($directory, $connection)) { ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ftp_chdir signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:348 +WARNING notSafeCall: potentially not safe call in function ftp_chdir signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:348 ftp_chdir($connection, $directory); ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/flysystem/src/Adapter/Ftp.php:370 @@ -157,10 +157,10 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_chdir signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:391 if (@ftp_chdir($this->getConnection(), $path) === true) { ^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter subject of function preg_match at testdata/flysystem/src/Adapter/Ftp.php:403 +WARNING notSafeCall: potentially not safe array access in parameter subject of function preg_match at testdata/flysystem/src/Adapter/Ftp.php:403 if (preg_match('/.* not found/', $listing[0])) { ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter subject of function preg_match at testdata/flysystem/src/Adapter/Ftp.php:407 +WARNING notSafeCall: potentially not safe array access in parameter subject of function preg_match at testdata/flysystem/src/Adapter/Ftp.php:407 if (preg_match('/^total [0-9]*$/', $listing[0])) { ^^^^^^^^^^^ MAYBE regexpSimplify: May re-write '/^total [0-9]*$/' as '/^total \d*$/' at testdata/flysystem/src/Adapter/Ftp.php:407 @@ -175,13 +175,13 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_mdtm signature of param filename at testdata/flysystem/src/Adapter/Ftp.php:433 $timestamp = ftp_mdtm($this->getConnection(), $path); ^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter stream of function stream_get_contents at testdata/flysystem/src/Adapter/Ftp.php:447 +WARNING notSafeCall: potentially not safe array access in parameter stream of function stream_get_contents at testdata/flysystem/src/Adapter/Ftp.php:447 $object['contents'] = stream_get_contents($object['stream']); ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter stream of function fclose at testdata/flysystem/src/Adapter/Ftp.php:448 +WARNING notSafeCall: potentially not safe array access in parameter stream of function fclose at testdata/flysystem/src/Adapter/Ftp.php:448 fclose($object['stream']); ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ftp_fget signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:460 +WARNING notSafeCall: potentially not safe call in function ftp_fget signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:460 $result = ftp_fget($this->getConnection(), $stream, $path, $this->transferMode); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_fget signature of param remote_filename at testdata/flysystem/src/Adapter/Ftp.php:460 @@ -190,28 +190,28 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'transferMode' at testdata/flysystem/src/Adapter/Ftp.php:460 $result = ftp_fget($this->getConnection(), $stream, $path, $this->transferMode); ^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function rewind signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:461 +WARNING notSafeCall: potentially not safe call in function rewind signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:461 rewind($stream); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function fclose signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:464 +WARNING notSafeCall: potentially not safe call in function fclose signature of param stream at testdata/flysystem/src/Adapter/Ftp.php:464 fclose($stream); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_chmod signature of param filename at testdata/flysystem/src/Adapter/Ftp.php:479 if ( ! ftp_chmod($this->getConnection(), $mode, $path)) { ^^^^^ -WARNING notSafetyCall: potential not safety call in function listDirectoryContentsRecursive signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:496 +WARNING notSafeCall: potentially not safe call in function listDirectoryContentsRecursive signature of param directory at testdata/flysystem/src/Adapter/Ftp.php:496 return $this->listDirectoryContentsRecursive($directory); ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function normalizeListing signature of param prefix at testdata/flysystem/src/Adapter/Ftp.php:502 +WARNING notSafeCall: potentially not safe call in function normalizeListing signature of param prefix at testdata/flysystem/src/Adapter/Ftp.php:502 return $listing ? $this->normalizeListing($listing, $directory) : []; ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter directory of function listDirectoryContentsRecursive at testdata/flysystem/src/Adapter/Ftp.php:520 +WARNING notSafeCall: potentially not safe array access in parameter directory of function listDirectoryContentsRecursive at testdata/flysystem/src/Adapter/Ftp.php:520 $output = array_merge($output, $this->listDirectoryContentsRecursive($item['path'])); ^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'connection' at testdata/flysystem/src/Adapter/Ftp.php:544 $response = ftp_raw($this->connection, 'HELP'); ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ftp_rawlist signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:565 +WARNING notSafeCall: potentially not safe call in function ftp_rawlist signature of param ftp at testdata/flysystem/src/Adapter/Ftp.php:565 return ftp_rawlist($connection, $options . ' ' . $path); ^^^^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Ftp.php:570 @@ -232,22 +232,22 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function ftp_rawlist signature of param directory at testdata/flysystem/src/Adapter/Ftpd.php:37 $listing = ftp_rawlist($this->getConnection(), $directory, $recursive); ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function substr at testdata/flysystem/src/Adapter/Ftpd.php:39 +WARNING notSafeCall: potentially not safe array access in parameter string of function substr at testdata/flysystem/src/Adapter/Ftpd.php:39 if ($listing === false || ( ! empty($listing) && substr($listing[0], 0, 5) === "ftpd:")) { ^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function normalizeListing signature of param prefix at testdata/flysystem/src/Adapter/Ftpd.php:43 return $this->normalizeListing($listing, $directory); ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ensureDirectory signature of param root at testdata/flysystem/src/Adapter/Local.php:78 +WARNING notSafeCall: potentially not safe call in function ensureDirectory signature of param root at testdata/flysystem/src/Adapter/Local.php:78 $this->ensureDirectory($root); ^^^^^ -WARNING notSafetyCall: potential not safety call in function is_dir signature of param filename at testdata/flysystem/src/Adapter/Local.php:80 +WARNING notSafeCall: potentially not safe call in function is_dir signature of param filename at testdata/flysystem/src/Adapter/Local.php:80 if ( ! is_dir($root) || ! is_readable($root)) { ^^^^^ -WARNING notSafetyCall: potential not safety call in function is_readable signature of param filename at testdata/flysystem/src/Adapter/Local.php:80 +WARNING notSafeCall: potentially not safe call in function is_readable signature of param filename at testdata/flysystem/src/Adapter/Local.php:80 if ( ! is_dir($root) || ! is_readable($root)) { ^^^^^ -WARNING notSafetyCall: potential not safety call in function setPathPrefix signature of param prefix at testdata/flysystem/src/Adapter/Local.php:84 +WARNING notSafeCall: potentially not safe call in function setPathPrefix signature of param prefix at testdata/flysystem/src/Adapter/Local.php:84 $this->setPathPrefix($root); ^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Local.php:103 @@ -277,10 +277,10 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_copy_to_stream signature of param from at testdata/flysystem/src/Adapter/Local.php:159 if ( ! $stream || stream_copy_to_stream($resource, $stream) === false || ! fclose($stream)) { ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stream_copy_to_stream signature of param to at testdata/flysystem/src/Adapter/Local.php:159 +WARNING notSafeCall: potentially not safe call in function stream_copy_to_stream signature of param to at testdata/flysystem/src/Adapter/Local.php:159 if ( ! $stream || stream_copy_to_stream($resource, $stream) === false || ! fclose($stream)) { ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function fclose signature of param stream at testdata/flysystem/src/Adapter/Local.php:159 +WARNING notSafeCall: potentially not safe call in function fclose signature of param stream at testdata/flysystem/src/Adapter/Local.php:159 if ( ! $stream || stream_copy_to_stream($resource, $stream) === false || ! fclose($stream)) { ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:179 @@ -331,10 +331,10 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/flysystem/src/Adapter/Local.php:263 return @unlink($location); ^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function getFilePath signature of param file at testdata/flysystem/src/Adapter/Local.php:281 +WARNING notSafeCall: potentially not safe call in function getFilePath signature of param file at testdata/flysystem/src/Adapter/Local.php:281 $path = $this->getFilePath($file); ^^^^^ -WARNING notSafetyCall: potential not safety call in function normalizeFileInfo signature of param file at testdata/flysystem/src/Adapter/Local.php:287 +WARNING notSafeCall: potentially not safe call in function normalizeFileInfo signature of param file at testdata/flysystem/src/Adapter/Local.php:287 $result[] = $this->normalizeFileInfo($file); ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:300 @@ -349,7 +349,7 @@ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:344 $location = $this->applyPathPrefix($path); ^^^^^ -WARNING notSafetyCall: potential not safety call in function octdec signature of param octal_string when calling function \substr at testdata/flysystem/src/Adapter/Local.php:346 +WARNING notSafeCall: potentially not safe call in function octdec signature of param octal_string when calling function \substr at testdata/flysystem/src/Adapter/Local.php:346 $permissions = octdec(substr(sprintf('%o', fileperms($location)), -4)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:365 @@ -364,28 +364,28 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function applyPathPrefix signature of param path at testdata/flysystem/src/Adapter/Local.php:403 $location = $this->applyPathPrefix($dirname); ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function guardAgainstUnreadableFileInfo signature of param file at testdata/flysystem/src/Adapter/Local.php:413 +WARNING notSafeCall: potentially not safe call in function guardAgainstUnreadableFileInfo signature of param file at testdata/flysystem/src/Adapter/Local.php:413 $this->guardAgainstUnreadableFileInfo($file); ^^^^^ -WARNING notSafetyCall: potential not safety call in function deleteFileInfoObject signature of param file at testdata/flysystem/src/Adapter/Local.php:414 +WARNING notSafeCall: potentially not safe call in function deleteFileInfoObject signature of param file at testdata/flysystem/src/Adapter/Local.php:414 $this->deleteFileInfoObject($file); ^^^^^ MAYBE invalidDocblockType: Void type can only be used as a standalone type for the return type at testdata/flysystem/src/Adapter/Local.php:444 * @return array|void ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function trim signature of param string when calling function \str_replace at testdata/flysystem/src/Adapter/Local.php:471 +WARNING notSafeCall: potentially not safe call in function trim signature of param string when calling function \str_replace at testdata/flysystem/src/Adapter/Local.php:471 return trim(str_replace('\\', '/', $path), '/'); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING invalidDocblockRef: @see tag refers to unknown symbol League\Flysystem\ReadInterface::readStream at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:17 * @see League\Flysystem\ReadInterface::readStream() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function fwrite signature of param stream at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:26 +WARNING notSafeCall: potentially not safe call in function fwrite signature of param stream at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:26 fwrite($stream, $data['contents']); ^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter data of function fwrite at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:26 +WARNING notSafeCall: potentially not safe array access in parameter data of function fwrite at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:26 fwrite($stream, $data['contents']); ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function rewind signature of param stream at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:27 +WARNING notSafeCall: potentially not safe call in function rewind signature of param stream at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:27 rewind($stream); ^^^^^^^ WARNING invalidDocblockRef: @see tag refers to unknown symbol League\Flysystem\ReadInterface::read at testdata/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php:41 @@ -460,7 +460,7 @@ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or speci WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/flysystem/src/Handler.php:28 public function __construct(FilesystemInterface $filesystem = null, $path = null) ^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function mountFilesystem signature of param prefix at testdata/flysystem/src/MountManager.php:57 +WARNING notSafeCall: potentially not safe call in function mountFilesystem signature of param prefix at testdata/flysystem/src/MountManager.php:57 $this->mountFilesystem($prefix, $filesystem); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function mountFilesystem signature of param filesystem at testdata/flysystem/src/MountManager.php:57 @@ -472,7 +472,7 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function invokePluginOnFilesystem signature of param prefix at testdata/flysystem/src/MountManager.php:166 return $this->invokePluginOnFilesystem($method, $arguments, $prefix); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function writeStream signature of param resource at testdata/flysystem/src/MountManager.php:192 +WARNING notSafeCall: potentially not safe call in function writeStream signature of param resource at testdata/flysystem/src/MountManager.php:192 $result = $this->getFilesystem($prefixTo)->writeStream($to, $buffer, $config); ^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter visibility of function setVisibility at testdata/flysystem/src/MountManager.php:243 @@ -490,10 +490,10 @@ MAYBE deprecatedUntagged: Call to deprecated method {\League\Flysystem\Filesys WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/flysystem/src/MountManager.php:642 public function get($path, Handler $handler = null) ^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter dirname of function deleteDir at testdata/flysystem/src/Plugin/EmptyDir.php:28 +WARNING notSafeCall: potentially not safe array access in parameter dirname of function deleteDir at testdata/flysystem/src/Plugin/EmptyDir.php:28 $this->filesystem->deleteDir($item['path']); ^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter path of function delete at testdata/flysystem/src/Plugin/EmptyDir.php:30 +WARNING notSafeCall: potentially not safe array access in parameter path of function delete at testdata/flysystem/src/Plugin/EmptyDir.php:30 $this->filesystem->delete($item['path']); ^^^^^^^^^^^^^ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/Plugin/ForcedCopy.php:33 @@ -511,7 +511,7 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/flysystem/src/Plugin/PluggableTrait.php:72 return call_user_func_array($callback, $arguments); ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function invokePlugin signature of param filesystem at testdata/flysystem/src/Plugin/PluggableTrait.php:88 +WARNING notSafeCall: potentially not safe call in function invokePlugin signature of param filesystem at testdata/flysystem/src/Plugin/PluggableTrait.php:88 return $this->invokePlugin($method, $arguments, $this); ^^^^^ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/Plugin/PluggableTrait.php:89 @@ -529,7 +529,7 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE missingPhpdoc: Missing PHPDoc for \League\Flysystem\UnreadableFileException::forFileInfo public method at testdata/flysystem/src/UnreadableFileException.php:9 public static function forFileInfo(SplFileInfo $fileInfo) ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter path of function pathinfo at testdata/flysystem/src/Util.php:27 +WARNING notSafeCall: potentially not safe array access in parameter path of function pathinfo at testdata/flysystem/src/Util.php:27 $pathinfo += pathinfo($pathinfo['basename']); ^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function pathinfo signature of param path at testdata/flysystem/src/Util.php:214 @@ -595,6 +595,6 @@ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or speci MAYBE ternarySimplify: Could rewrite as `static::$extensionToMimeTypeMap[$extension] ?? 'text/plain'` at testdata/flysystem/src/Util/MimeType.php:222 return isset(static::$extensionToMimeTypeMap[$extension]) ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strtolower signature of param string when calling function \pathinfo at testdata/flysystem/src/Util/MimeType.php:234 +WARNING notSafeCall: potentially not safe call in function strtolower signature of param string when calling function \pathinfo at testdata/flysystem/src/Util/MimeType.php:234 $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/idn/golden.txt b/src/tests/golden/testdata/idn/golden.txt index 94ef9917..7faf6a8c 100644 --- a/src/tests/golden/testdata/idn/golden.txt +++ b/src/tests/golden/testdata/idn/golden.txt @@ -28,7 +28,7 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/idn/idn.php:119 $idna_info = array( -WARNING notSafetyCall: potential not safety call in function mb_chr signature of param codepoint at testdata/idn/idn.php:139 +WARNING notSafeCall: potentially not safe call in function mb_chr signature of param codepoint at testdata/idn/idn.php:139 $output .= mb_chr($code, 'utf-8'); ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function mb_strlen signature of param string at testdata/idn/idn.php:152 @@ -67,7 +67,7 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/idn/idn.php:249 $output = substr($input, 0, $pos++); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/idn/idn.php:254 +WARNING notSafeCall: potentially not safe call in function strlen signature of param string at testdata/idn/idn.php:254 $outputLength = \strlen($output); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/idn/idn.php:255 @@ -79,15 +79,15 @@ MAYBE assignOp: Could rewrite as `$n += (int) ($i / $outputLength)` at testdat MAYBE assignOp: Could rewrite as `$i %= $outputLength` at testdata/idn/idn.php:275 $i = $i % $outputLength; ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function mb_substr signature of param string at testdata/idn/idn.php:276 +WARNING notSafeCall: potentially not safe call in function mb_substr signature of param string at testdata/idn/idn.php:276 $output = mb_substr($output, 0, $i, 'utf-8').mb_chr($n, 'utf-8').mb_substr($output, $i, $outputLength - 1, 'utf-8'); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function mb_substr signature of param length at testdata/idn/idn.php:276 +WARNING notSafeCall: potentially not safe call in function mb_substr signature of param length at testdata/idn/idn.php:276 $output = mb_substr($output, 0, $i, 'utf-8').mb_chr($n, 'utf-8').mb_substr($output, $i, $outputLength - 1, 'utf-8'); ^^ -WARNING notSafetyCall: potential not safety call in function mb_substr signature of param string at testdata/idn/idn.php:276 +WARNING notSafeCall: potentially not safe call in function mb_substr signature of param string at testdata/idn/idn.php:276 $output = mb_substr($output, 0, $i, 'utf-8').mb_chr($n, 'utf-8').mb_substr($output, $i, $outputLength - 1, 'utf-8'); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function mb_substr signature of param start at testdata/idn/idn.php:276 +WARNING notSafeCall: potentially not safe call in function mb_substr signature of param start at testdata/idn/idn.php:276 $output = mb_substr($output, 0, $i, 'utf-8').mb_chr($n, 'utf-8').mb_substr($output, $i, $outputLength - 1, 'utf-8'); ^^ diff --git a/src/tests/golden/testdata/math/golden.txt b/src/tests/golden/testdata/math/golden.txt index cec9e307..811fcbb4 100644 --- a/src/tests/golden/testdata/math/golden.txt +++ b/src/tests/golden/testdata/math/golden.txt @@ -1,25 +1,25 @@ WARNING unused: Variable $a is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/math/src/BigDecimal.php:292 [$a, $b] = $this->scaleValues($this, $that); ^^ -WARNING notSafetyCall: potential not safety call in function str_repeat signature of param times at testdata/math/src/BigDecimal.php:464 +WARNING notSafeCall: potentially not safe call in function str_repeat signature of param times at testdata/math/src/BigDecimal.php:464 $value .= \str_repeat('0', $addDigits); ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param length at testdata/math/src/BigDecimal.php:472 +WARNING notSafeCall: potentially not safe call in function substr signature of param length at testdata/math/src/BigDecimal.php:472 $value = \substr($value, 0, $addDigits); ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function sqrt signature of param n at testdata/math/src/BigDecimal.php:475 +WARNING notSafeCall: potentially not safe call in function sqrt signature of param n at testdata/math/src/BigDecimal.php:475 $value = Calculator::get()->sqrt($value); ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function of signature of param value at testdata/math/src/BigDecimal.php:588 $that = BigNumber::of($that); ^^^^^ -WARNING notSafetyCall: potential not safety call in function str_pad signature of param string at testdata/math/src/BigDecimal.php:847 +WARNING notSafeCall: potentially not safe call in function str_pad signature of param string at testdata/math/src/BigDecimal.php:847 $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function str_pad signature of param length at testdata/math/src/BigDecimal.php:847 +WARNING notSafeCall: potentially not safe call in function str_pad signature of param length at testdata/math/src/BigDecimal.php:847 $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT); ^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ltrim signature of param string at testdata/math/src/BigInteger.php:105 +WARNING notSafeCall: potentially not safe call in function ltrim signature of param string at testdata/math/src/BigInteger.php:105 $number = \ltrim($number, '0'); ^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/math/src/BigInteger.php:435 @@ -28,34 +28,34 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function of signature of param value at testdata/math/src/BigInteger.php:742 $that = BigNumber::of($that); ^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/math/src/BigNumber.php:74 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/math/src/BigNumber.php:74 if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) { ^^^^^^ MAYBE ternarySimplify: Could rewrite as `$matches['fractional'] ?? ''` at testdata/math/src/BigNumber.php:90 $fractional = isset($matches['fractional']) ? $matches['fractional'] : ''; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function setlocale signature of param rest at testdata/math/src/BigNumber.php:131 +WARNING notSafeCall: potentially not safe call in function setlocale signature of param rest at testdata/math/src/BigNumber.php:131 \setlocale(LC_NUMERIC, $currentLocale); ^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function of signature of param value at testdata/math/src/BigNumber.php:171 +WARNING notSafeCall: potentially not safe call in function of signature of param value at testdata/math/src/BigNumber.php:171 $value = static::of($value); ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function isLessThan signature of param that at testdata/math/src/BigNumber.php:173 if ($min === null || $value->isLessThan($min)) { ^^^^ -WARNING notSafetyCall: potential not safety call in function of signature of param value at testdata/math/src/BigNumber.php:203 +WARNING notSafeCall: potentially not safe call in function of signature of param value at testdata/math/src/BigNumber.php:203 $value = static::of($value); ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function isGreaterThan signature of param that at testdata/math/src/BigNumber.php:205 if ($max === null || $value->isGreaterThan($max)) { ^^^^ -WARNING notSafetyCall: potential not safety call in function of signature of param value at testdata/math/src/BigNumber.php:236 +WARNING notSafeCall: potentially not safe call in function of signature of param value at testdata/math/src/BigNumber.php:236 $value = static::of($value); ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function add signature of param a at testdata/math/src/BigNumber.php:241 $sum = self::add($sum, $value); ^^^^ -WARNING notSafetyCall: potential not safety call in function ltrim signature of param string at testdata/math/src/BigNumber.php:307 +WARNING notSafeCall: potentially not safe call in function ltrim signature of param string at testdata/math/src/BigNumber.php:307 $number = \ltrim($number, '0'); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function minus signature of param that at testdata/math/src/BigRational.php:365 @@ -64,13 +64,13 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE implicitModifiers: Specify the access modifier for \Brick\Math\Internal\Calculator::powmod method explicitly at testdata/math/src/Internal/Calculator.php:260 abstract function powmod(string $base, string $exp, string $mod) : string; ^^^^^^ -WARNING notSafetyCall: potential not safety call in function toArbitraryBase signature of param number at testdata/math/src/Internal/Calculator.php:333 +WARNING notSafeCall: potentially not safe call in function toArbitraryBase signature of param number at testdata/math/src/Internal/Calculator.php:333 $number = $this->toArbitraryBase($number, self::ALPHABET, $base); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function twosComplement signature of param number at testdata/math/src/Internal/Calculator.php:605 +WARNING notSafeCall: potentially not safe call in function twosComplement signature of param number at testdata/math/src/Internal/Calculator.php:605 $value = $this->twosComplement($value); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function toDecimal signature of param bytes at testdata/math/src/Internal/Calculator.php:608 +WARNING notSafeCall: potentially not safe call in function toDecimal signature of param bytes at testdata/math/src/Internal/Calculator.php:608 $result = $this->toDecimal($value); ^^^^^^ MAYBE assignOp: Could rewrite as `$number ^= $xor` at testdata/math/src/Internal/Calculator.php:622 @@ -85,25 +85,25 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/math/src/Internal/Calculator/GmpCalculator.php:67 \gmp_strval($r) ^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function neg signature of param n at testdata/math/src/Internal/Calculator/NativeCalculator.php:79 +WARNING notSafeCall: potentially not safe call in function neg signature of param n at testdata/math/src/Internal/Calculator/NativeCalculator.php:79 $result = $this->neg($result); ^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/math/src/Internal/Calculator/NativeCalculator.php:187 (string) $r ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:322 +WARNING notSafeCall: potentially not safe call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:322 $blockA = \substr($a, $i, $blockLength); ^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:323 +WARNING notSafeCall: potentially not safe call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:323 $blockB = \substr($b, $i, $blockLength); ^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:392 +WARNING notSafeCall: potentially not safe call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:392 $blockA = \substr($a, $i, $blockLength); ^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:393 +WARNING notSafeCall: potentially not safe call in function substr signature of param offset at testdata/math/src/Internal/Calculator/NativeCalculator.php:393 $blockB = \substr($b, $i, $blockLength); ^^ -WARNING notSafetyCall: potential not safety call in function doCmp signature of param a at testdata/math/src/Internal/Calculator/NativeCalculator.php:532 +WARNING notSafeCall: potentially not safe call in function doCmp signature of param a at testdata/math/src/Internal/Calculator/NativeCalculator.php:532 $cmp = $this->doCmp($focus, $b); ^^^^^^ ERROR classMembersOrder: Constant UNNECESSARY must go before methods in the class RoundingMode at testdata/math/src/RoundingMode.php:33 diff --git a/src/tests/golden/testdata/mustache/golden.txt b/src/tests/golden/testdata/mustache/golden.txt index 79d84ec9..38e42adc 100644 --- a/src/tests/golden/testdata/mustache/golden.txt +++ b/src/tests/golden/testdata/mustache/golden.txt @@ -1,13 +1,13 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function realpath signature of param path at testdata/mustache/src/Mustache/Autoloader.php:39 $realDir = realpath($baseDir); ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function is_dir signature of param filename at testdata/mustache/src/Mustache/Autoloader.php:40 +WARNING notSafeCall: potentially not safe call in function is_dir signature of param filename at testdata/mustache/src/Mustache/Autoloader.php:40 if (is_dir($realDir)) { ^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$baseDir ?: 0` at testdata/mustache/src/Mustache/Autoloader.php:56 $key = $baseDir ? $baseDir : 0; ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strpos signature of param haystack at testdata/mustache/src/Mustache/Autoloader.php:79 +WARNING notSafeCall: potentially not safe call in function strpos signature of param haystack at testdata/mustache/src/Mustache/Autoloader.php:79 if (strpos($class, 'Mustache') !== 0) { ^^^^^^ ERROR undefinedClass: Class or interface named \Psr\Log\LoggerInterface does not exist at testdata/mustache/src/Mustache/Cache/AbstractCache.php:26 @@ -22,13 +22,13 @@ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:140 if (false !== @file_put_contents($tempFile, $value)) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function file_put_contents signature of param filename at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:140 +WARNING notSafeCall: potentially not safe call in function file_put_contents signature of param filename at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:140 if (false !== @file_put_contents($tempFile, $value)) { ^^^^^^^^^ WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:141 if (@rename($tempFile, $fileName)) { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function rename signature of param from at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:141 +WARNING notSafeCall: potentially not safe call in function rename signature of param from at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:141 if (@rename($tempFile, $fileName)) { ^^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$this->fileMode ?? (0666 & ~umask())` at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:142 @@ -37,7 +37,7 @@ MAYBE ternarySimplify: Could rewrite as `$this->fileMode ?? (0666 & ~umask())` WARNING errorSilence: Don't use @, silencing errors is bad practice at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:143 @chmod($fileName, $mode); ^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function chmod signature of param permissions at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:143 +WARNING notSafeCall: potentially not safe call in function chmod signature of param permissions at testdata/mustache/src/Mustache/Cache/FilesystemCache.php:143 @chmod($fileName, $mode); ^^^^^ WARNING useEval: Don't use the 'eval' function at testdata/mustache/src/Mustache/Cache/NoopCache.php:45 @@ -232,7 +232,7 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access MAYBE misspellComment: "entitity" is a misspelling of "entity" at testdata/mustache/src/Mustache/Engine.php:254 public function getEntityFlags() ^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function addHelper signature of param name at testdata/mustache/src/Mustache/Engine.php:373 +WARNING notSafeCall: potentially not safe call in function addHelper signature of param name at testdata/mustache/src/Mustache/Engine.php:373 $this->addHelper($name, $helper); ^^^^^ ERROR undefinedClass: Class or interface named \Psr\Log\LoggerInterface does not exist at testdata/mustache/src/Mustache/Engine.php:451 @@ -256,13 +256,13 @@ ERROR undefinedMethod: Call to undefined method {\Mustache_Cache}->setLogger() MAYBE ternarySimplify: Could rewrite as `$this->delimiters ?: '{{ }}'` at testdata/mustache/src/Mustache/Engine.php:628 'delimiters' => $this->delimiters ? $this->delimiters : '{{ }}', ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function md5 signature of param string at testdata/mustache/src/Mustache/Engine.php:645 +WARNING notSafeCall: potentially not safe call in function md5 signature of param string at testdata/mustache/src/Mustache/Engine.php:645 return $this->templateClassPrefix . md5($key); ^^^^ -WARNING notSafetyCall: potential not safety call in function parse signature of param source at testdata/mustache/src/Mustache/Engine.php:808 +WARNING notSafeCall: potentially not safe call in function parse signature of param source at testdata/mustache/src/Mustache/Engine.php:808 $tree = $this->parse($source); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function compile signature of param source at testdata/mustache/src/Mustache/Engine.php:813 +WARNING notSafeCall: potentially not safe call in function compile signature of param source at testdata/mustache/src/Mustache/Engine.php:813 return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags); ^^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'charset' at testdata/mustache/src/Mustache/Engine.php:813 @@ -295,40 +295,40 @@ MAYBE missingPhpdoc: Missing PHPDoc for \Mustache_Exception_UnknownTemplateExc WARNING notExplicitNullableParam: parameter with null default value should be explicitly nullable at testdata/mustache/src/Mustache/Exception/UnknownTemplateException.php:23 public function __construct($templateName, Exception $previous = null) ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function add signature of param name at testdata/mustache/src/Mustache/HelperCollection.php:39 +WARNING notSafeCall: potentially not safe call in function add signature of param name at testdata/mustache/src/Mustache/HelperCollection.php:39 $this->add($name, $helper); ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function addLoader signature of param loader at testdata/mustache/src/Mustache/Loader/CascadingLoader.php:35 $this->addLoader($loader); ^^^^^^^ -WARNING notSafetyCall: potential not safety accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:52 +WARNING notSafeCall: potentially not safe accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:52 if (strpos($this->baseDir, '://') === false) { ^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:53 +WARNING notSafeCall: potentially not safe accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:53 $this->baseDir = realpath($this->baseDir); ^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:56 +WARNING notSafeCall: potentially not safe accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:56 if ($this->shouldCheckPath() && !is_dir($this->baseDir)) { ^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function ltrim at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:64 $this->extension = '.' . ltrim($options['extension'], '.'); ^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:133 +WARNING notSafeCall: potentially not safe accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:133 return strpos($this->baseDir, '://') === false || strpos($this->baseDir, 'file://') === 0; ^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:133 +WARNING notSafeCall: potentially not safe accessing property 'baseDir' at testdata/mustache/src/Mustache/Loader/FilesystemLoader.php:133 return strpos($this->baseDir, '://') === false || strpos($this->baseDir, 'file://') === 0; ^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentConstFetch: null passed to non-nullable parameter context in function file_get_contents at testdata/mustache/src/Mustache/Loader/InlineLoader.php:114 $data = file_get_contents($this->fileName, false, null, $this->offset); ^^^^ -WARNING notSafetyCall: potential not safety call in function preg_split signature of param subject at testdata/mustache/src/Mustache/Loader/InlineLoader.php:115 +WARNING notSafeCall: potentially not safe call in function preg_split signature of param subject at testdata/mustache/src/Mustache/Loader/InlineLoader.php:115 foreach (preg_split("/^@@(?= [\w\d\.]+$)/m", $data, -1) as $chunk) { ^^^^^ WARNING regexpVet: '\w' intersects with '\d' in [\w\d\.] at testdata/mustache/src/Mustache/Loader/InlineLoader.php:115 foreach (preg_split("/^@@(?= [\w\d\.]+$)/m", $data, -1) as $chunk) { ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function setLevel signature of param level at testdata/mustache/src/Mustache/Logger/StreamLogger.php:46 +WARNING notSafeCall: potentially not safe call in function setLevel signature of param level at testdata/mustache/src/Mustache/Logger/StreamLogger.php:46 $this->setLevel($level); ^^^^^^ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'stream' at testdata/mustache/src/Mustache/Logger/StreamLogger.php:61 @@ -346,7 +346,7 @@ WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference w WARNING notNullSafetyFunctionArgumentPropertyFetch: potential null dereference when accessing property 'stream' at testdata/mustache/src/Mustache/Logger/StreamLogger.php:136 fwrite($this->stream, self::formatLine($level, $message, $context)); ^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strtoupper signature of param string at testdata/mustache/src/Mustache/Logger/StreamLogger.php:150 +WARNING notSafeCall: potentially not safe call in function strtoupper signature of param string at testdata/mustache/src/Mustache/Logger/StreamLogger.php:150 return strtoupper($level); ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function enablePragma signature of param name at testdata/mustache/src/Mustache/Parser.php:58 @@ -382,30 +382,30 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function trim signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:110 if ($delimiters = trim($delimiters)) { ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function changeDelimiters signature of param index at testdata/mustache/src/Mustache/Tokenizer.php:145 +WARNING notSafeCall: potentially not safe call in function changeDelimiters signature of param index at testdata/mustache/src/Mustache/Tokenizer.php:145 $i = $this->changeDelimiters($text, $i); ^^ -WARNING notSafetyCall: potential not safety call in function addPragma signature of param index at testdata/mustache/src/Mustache/Tokenizer.php:148 +WARNING notSafeCall: potentially not safe call in function addPragma signature of param index at testdata/mustache/src/Mustache/Tokenizer.php:148 $i = $this->addPragma($text, $i); ^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:188 if (substr($lastName, -1) === '}') { ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function trim signature of param string when calling function \substr at testdata/mustache/src/Mustache/Tokenizer.php:189 +WARNING notSafeCall: potentially not safe call in function trim signature of param string when calling function \substr at testdata/mustache/src/Mustache/Tokenizer.php:189 $token[self::NAME] = trim(substr($lastName, 0, -1)); ^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/mustache/src/Mustache/Tokenizer.php:189 $token[self::NAME] = trim(substr($lastName, 0, -1)); ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function trim signature of param string when calling function \substr at testdata/mustache/src/Mustache/Tokenizer.php:283 +WARNING notSafeCall: potentially not safe call in function trim signature of param string when calling function \substr at testdata/mustache/src/Mustache/Tokenizer.php:283 $this->setDelimiters(trim(substr($text, $startIndex, $closeIndex - $startIndex))); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/mustache/src/Mustache/Tokenizer.php:283 +WARNING notSafeCall: potentially not safe call in function substr signature of param offset at testdata/mustache/src/Mustache/Tokenizer.php:283 $this->setDelimiters(trim(substr($text, $startIndex, $closeIndex - $startIndex))); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety accessing property 'ctag' at testdata/mustache/src/Mustache/Tokenizer.php:330 +WARNING notSafeCall: potentially not safe accessing property 'ctag' at testdata/mustache/src/Mustache/Tokenizer.php:330 $end = strpos($text, $this->ctag, $index); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function trim signature of param string when calling function \substr at testdata/mustache/src/Mustache/Tokenizer.php:331 +WARNING notSafeCall: potentially not safe call in function trim signature of param string when calling function \substr at testdata/mustache/src/Mustache/Tokenizer.php:331 $pragma = trim(substr($text, $index + 2, $end - $index - 2)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tests/golden/testdata/options-resolver/golden.txt b/src/tests/golden/testdata/options-resolver/golden.txt index 49dbbaca..56737f6b 100644 --- a/src/tests/golden/testdata/options-resolver/golden.txt +++ b/src/tests/golden/testdata/options-resolver/golden.txt @@ -31,7 +31,7 @@ MAYBE deprecated: Call to deprecated method {\ReflectionParameter}->getClass() MAYBE deprecated: Call to deprecated method {\ReflectionParameter}->getClass() (since: 8.0, reason: Use ReflectionParameter::getType() and the ReflectionType APIs should be used instead) at testdata/options-resolver/OptionsResolver.php:209 if (isset($params[0]) && null !== ($class = $params[0]->getClass()) && self::class === $class->name && (!isset($params[1]) || (null !== ($class = $params[1]->getClass()) && Options::class === $class->name))) { ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function setDefault signature of param option at testdata/options-resolver/OptionsResolver.php:251 +WARNING notSafeCall: potentially not safe call in function setDefault signature of param option at testdata/options-resolver/OptionsResolver.php:251 $this->setDefault($option, $value); ^^^^^^^ WARNING invalidDocblock: @param for non-existing argument $package at testdata/options-resolver/OptionsResolver.php:424 @@ -43,46 +43,46 @@ WARNING invalidDocblock: @param for non-existing argument $version at testdata/o WARNING invalidDocblock: @param for non-existing argument $message at testdata/options-resolver/OptionsResolver.php:426 * @param string|\Closure $message The deprecation message to use ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function offsetGet signature of param option at testdata/options-resolver/OptionsResolver.php:895 +WARNING notSafeCall: potentially not safe call in function offsetGet signature of param option at testdata/options-resolver/OptionsResolver.php:895 $clone->offsetGet($option); ^^^^^^^ MAYBE complexity: Too big method: more than 150 lines at testdata/options-resolver/OptionsResolver.php:917 public function offsetGet($option, bool $triggerDeprecation = true) ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1000 +WARNING notSafeCall: potentially not safe call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1000 if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1000 if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { ^^^^^^ -WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1000 +WARNING notSafeCall: potentially not safe call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1000 if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1000 if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) { ^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter package of function trigger_deprecation at testdata/options-resolver/OptionsResolver.php:1090 +WARNING notSafeCall: potentially not safe array access in parameter package of function trigger_deprecation at testdata/options-resolver/OptionsResolver.php:1090 trigger_deprecation($deprecation['package'], $deprecation['version'], strtr($message, ['%name%' => $option])); ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter version of function trigger_deprecation at testdata/options-resolver/OptionsResolver.php:1090 +WARNING notSafeCall: potentially not safe array access in parameter version of function trigger_deprecation at testdata/options-resolver/OptionsResolver.php:1090 trigger_deprecation($deprecation['package'], $deprecation['version'], strtr($message, ['%name%' => $option])); ^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strtr signature of param str at testdata/options-resolver/OptionsResolver.php:1090 +WARNING notSafeCall: potentially not safe call in function strtr signature of param str at testdata/options-resolver/OptionsResolver.php:1090 trigger_deprecation($deprecation['package'], $deprecation['version'], strtr($message, ['%name%' => $option])); ^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $invalidTypes in PHPDoc, 'array' type hint too generic at testdata/options-resolver/OptionsResolver.php:1123 private function verifyTypes(string $type, $value, array &$invalidTypes, int $level = 0): bool ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1130 +WARNING notSafeCall: potentially not safe call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1130 if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { ^^^^^ -WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1130 +WARNING notSafeCall: potentially not safe call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1130 if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { ^^^^ -WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1130 +WARNING notSafeCall: potentially not safe call in function verifyTypes signature of param type at testdata/options-resolver/OptionsResolver.php:1130 if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { ^^^^^ -WARNING notSafetyCall: potential not safety call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1130 +WARNING notSafeCall: potentially not safe call in function verifyTypes signature of param value at testdata/options-resolver/OptionsResolver.php:1130 if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { ^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function get_class signature of param object at testdata/options-resolver/OptionsResolver.php:1221 diff --git a/src/tests/golden/testdata/parsedown/golden.txt b/src/tests/golden/testdata/parsedown/golden.txt index 09f24541..50b833e3 100644 --- a/src/tests/golden/testdata/parsedown/golden.txt +++ b/src/tests/golden/testdata/parsedown/golden.txt @@ -1,7 +1,7 @@ MAYBE implicitModifiers: Specify the access modifier for \Parsedown::text method explicitly at testdata/parsedown/parsedown.php:24 function text($text) ^^^^ -WARNING notSafetyCall: potential not safety call in function trim signature of param string at testdata/parsedown/parsedown.php:46 +WARNING notSafeCall: potentially not safe call in function trim signature of param string at testdata/parsedown/parsedown.php:46 $text = trim($text, "\n"); ^^^^^ MAYBE implicitModifiers: Specify the access modifier for \Parsedown::setBreaksEnabled method explicitly at testdata/parsedown/parsedown.php:59 @@ -31,16 +31,16 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strstr signature of param haystack at testdata/parsedown/parsedown.php:186 while (($beforeTab = strstr($line, "\t", true)) !== false) ^^^^^ -WARNING notSafetyCall: potential not safety call in function mb_strlen signature of param string at testdata/parsedown/parsedown.php:188 +WARNING notSafeCall: potentially not safe call in function mb_strlen signature of param string at testdata/parsedown/parsedown.php:188 $shortage = 4 - mb_strlen($beforeTab, 'utf-8') % 4; ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function str_repeat signature of param times at testdata/parsedown/parsedown.php:191 +WARNING notSafeCall: potentially not safe call in function str_repeat signature of param times at testdata/parsedown/parsedown.php:191 . str_repeat(' ', $shortage) ^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:192 . substr($line, strlen($beforeTab) + 1) ^^^^^ -WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:192 +WARNING notSafeCall: potentially not safe call in function strlen signature of param string at testdata/parsedown/parsedown.php:192 . substr($line, strlen($beforeTab) + 1) ^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strspn signature of param string at testdata/parsedown/parsedown.php:196 @@ -79,7 +79,7 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strspn signature of param characters at testdata/parsedown/parsedown.php:452 $openerLength = strspn($Line['text'], $marker); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function trim signature of param string when calling function \substr at testdata/parsedown/parsedown.php:459 +WARNING notSafeCall: potentially not safe call in function trim signature of param string when calling function \substr at testdata/parsedown/parsedown.php:459 $infostring = trim(substr($Line['text'], $openerLength), "\t "); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:459 @@ -100,7 +100,7 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter characters of function strspn at testdata/parsedown/parsedown.php:516 if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength'] ^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function chop signature of param string when calling function \substr at testdata/parsedown/parsedown.php:517 +WARNING notSafeCall: potentially not safe call in function chop signature of param string when calling function \substr at testdata/parsedown/parsedown.php:517 and chop(substr($Line['text'], $len), ' ') === '' ^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:517 @@ -121,16 +121,16 @@ MAYBE typeHint: Specify the type for the parameter $CurrentBlock in PHPDoc, 'a WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:578 if (preg_match('/^('.$pattern.'([ ]++|$))(.*+)/', $Line['text'], $matches)) ^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter haystack of function strstr at testdata/parsedown/parsedown.php:593 +WARNING notSafeCall: potentially not safe array access in parameter haystack of function strstr at testdata/parsedown/parsedown.php:593 $markerWithoutWhitespace = strstr($matches[1], ' ', true); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/parsedown/parsedown.php:601 +WARNING notSafeCall: potentially not safe call in function substr signature of param string at testdata/parsedown/parsedown.php:601 'markerType' => ($name === 'ul' ? $markerWithoutWhitespace : substr($markerWithoutWhitespace, -1)), ^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ltrim signature of param string when calling function \strstr at testdata/parsedown/parsedown.php:612 +WARNING notSafeCall: potentially not safe call in function ltrim signature of param string when calling function \strstr at testdata/parsedown/parsedown.php:612 $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter haystack of function strstr at testdata/parsedown/parsedown.php:612 +WARNING notSafeCall: potentially not safe array access in parameter haystack of function strstr at testdata/parsedown/parsedown.php:612 $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; ^^^^^^^^^^^ MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/parsedown/parsedown.php:633 @@ -148,7 +148,7 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:659 and preg_match('/^'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) ^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:659 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:659 and preg_match('/^'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) ^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$matches[1] ?? ''` at testdata/parsedown/parsedown.php:674 @@ -163,7 +163,7 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:712 $text = substr($Line['body'], $requiredIndent); ^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/parsedown/parsedown.php:712 +WARNING notSafeCall: potentially not safe call in function substr signature of param offset at testdata/parsedown/parsedown.php:712 $text = substr($Line['body'], $requiredIndent); ^^^^^^^^^^^^^^^ MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:729 @@ -262,28 +262,28 @@ MAYBE trailingComma: Last element in a multi-line array should have a trailing MAYBE typeHint: Specify the type for the parameter $Block in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1093 protected function paragraphContinue($Line, array $Block) ^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function lineElements signature of param nonNestables at testdata/parsedown/parsedown.php:1132 +WARNING notSafeCall: potentially not safe call in function lineElements signature of param nonNestables at testdata/parsedown/parsedown.php:1132 return $this->elements($this->lineElements($text, $nonNestables)); ^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strpbrk signature of param string at testdata/parsedown/parsedown.php:1149 +WARNING notSafeCall: potentially not safe call in function strpbrk signature of param string at testdata/parsedown/parsedown.php:1149 while ($excerpt = strpbrk($text, $this->inlineMarkerList)) ^^^^^ -WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1153 +WARNING notSafeCall: potentially not safe call in function strlen signature of param string at testdata/parsedown/parsedown.php:1153 $markerPosition = strlen($text) - strlen($excerpt); ^^^^^ -WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1153 +WARNING notSafeCall: potentially not safe call in function strlen signature of param string at testdata/parsedown/parsedown.php:1153 $markerPosition = strlen($text) - strlen($excerpt); ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1196 +WARNING notSafeCall: potentially not safe call in function substr signature of param string at testdata/parsedown/parsedown.php:1196 $unmarkedText = substr($text, 0, $Inline['position']); ^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1206 +WARNING notSafeCall: potentially not safe call in function substr signature of param string at testdata/parsedown/parsedown.php:1206 $text = substr($text, $Inline['position'] + $Inline['extent']); ^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1213 +WARNING notSafeCall: potentially not safe call in function substr signature of param string at testdata/parsedown/parsedown.php:1213 $unmarkedText = substr($text, 0, $markerPosition + 1); ^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1218 +WARNING notSafeCall: potentially not safe call in function substr signature of param string at testdata/parsedown/parsedown.php:1218 $text = substr($text, $markerPosition + 1); ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1242 @@ -322,7 +322,7 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1421 if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1421 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1421 if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) ^^^^^^^^ MAYBE regexpSimplify: May re-write '/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/' as '/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?: +("[^"]*+"|'[^']*+'))?\s*+[)]/' at testdata/parsedown/parsedown.php:1421 @@ -331,7 +331,7 @@ MAYBE regexpSimplify: May re-write '/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1434 if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1434 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1434 if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) ^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strtolower signature of param string at testdata/parsedown/parsedown.php:1437 @@ -349,13 +349,13 @@ MAYBE regexpSimplify: May re-write '/^<\/\w[\w-]*+[ ]*+>/s' as '/^<\/\w[\w-]*+ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1478 if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1478 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1478 if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) ^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter subject of function preg_match at testdata/parsedown/parsedown.php:1486 if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches)) ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1486 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param matches at testdata/parsedown/parsedown.php:1486 if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches)) ^^^^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter string of function substr at testdata/parsedown/parsedown.php:1497 @@ -445,7 +445,7 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1832 $before = substr($text, 0, $offset); ^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param length at testdata/parsedown/parsedown.php:1832 +WARNING notSafeCall: potentially not safe call in function substr signature of param length at testdata/parsedown/parsedown.php:1832 $before = substr($text, 0, $offset); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1833 @@ -457,7 +457,7 @@ MAYBE implicitModifiers: Specify the access modifier for \Parsedown::parse met MAYBE typeHint: Specify the type for the parameter $Element in PHPDoc, 'array' type hint too generic at testdata/parsedown/parsedown.php:1861 protected function sanitiseElement(array $Element) ^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1885 +WARNING notSafeCall: potentially not safe call in function preg_match signature of param subject at testdata/parsedown/parsedown.php:1885 if ( ! preg_match($goodAttribute, $att)) ^^^^ WARNING unused: Variable $val is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/parsedown/parsedown.php:1882 @@ -475,7 +475,7 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/parsedown/parsedown.php:1928 if ($len > strlen($string)) ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strtolower signature of param string when calling function \substr at testdata/parsedown/parsedown.php:1934 +WARNING notSafeCall: potentially not safe call in function strtolower signature of param string when calling function \substr at testdata/parsedown/parsedown.php:1934 return strtolower(substr($string, 0, $len)) === strtolower($needle); ^^^^^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/parsedown/parsedown.php:1934 diff --git a/src/tests/golden/testdata/phprocksyd/golden.txt b/src/tests/golden/testdata/phprocksyd/golden.txt index 45c428eb..007c8f92 100644 --- a/src/tests/golden/testdata/phprocksyd/golden.txt +++ b/src/tests/golden/testdata/phprocksyd/golden.txt @@ -31,16 +31,16 @@ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phpro WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_socket_accept signature of param socket at testdata/phprocksyd/Phprocksyd.php:200 $client = stream_socket_accept($server, self::ACCEPT_TIMEOUT, $peername); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_read_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:207 +WARNING notSafeCall: potentially not safe call in function stream_set_read_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:207 stream_set_read_buffer($client, 0); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_write_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:208 +WARNING notSafeCall: potentially not safe call in function stream_set_write_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:208 stream_set_write_buffer($client, 0); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_blocking signature of param stream at testdata/phprocksyd/Phprocksyd.php:209 +WARNING notSafeCall: potentially not safe call in function stream_set_blocking signature of param stream at testdata/phprocksyd/Phprocksyd.php:209 stream_set_blocking($client, 0); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_timeout signature of param stream at testdata/phprocksyd/Phprocksyd.php:210 +WARNING notSafeCall: potentially not safe call in function stream_set_timeout signature of param stream at testdata/phprocksyd/Phprocksyd.php:210 stream_set_timeout($client, self::CONN_TIMEOUT); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function pcntl_wait signature of param status at testdata/phprocksyd/Phprocksyd.php:231 @@ -52,10 +52,10 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rtrim signature of param string at testdata/phprocksyd/Phprocksyd.php:272 $req = rtrim($req); ^^^^ -WARNING notSafetyCall: potential not safety call in function fwrite signature of param data when calling function \substr at testdata/phprocksyd/Phprocksyd.php:295 +WARNING notSafeCall: potentially not safe call in function fwrite signature of param data when calling function \substr at testdata/phprocksyd/Phprocksyd.php:295 $wrote = fwrite($this->streams[$stream_id], substr($this->write_buf[$stream_id], 0, 65536)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/phprocksyd/Phprocksyd.php:309 +WARNING notSafeCall: potentially not safe call in function substr signature of param offset at testdata/phprocksyd/Phprocksyd.php:309 $this->write_buf[$stream_id] = substr($this->write_buf[$stream_id], $wrote); ^^^^^^ ERROR constCase: Constant 'NULL' should be used in lower case as 'null' at testdata/phprocksyd/Phprocksyd.php:321 @@ -97,7 +97,7 @@ WARNING invalidDocblock: Malformed @param $stream_id tag (maybe type is missing? WARNING invalidDocblock: Malformed @param $req tag (maybe type is missing?) at testdata/phprocksyd/Phprocksyd.php:422 * @param $req ^^^^ -WARNING notSafetyCall: potential not safety call in function posix_kill signature of param process_id at testdata/phprocksyd/Phprocksyd.php:438 +WARNING notSafeCall: potentially not safe call in function posix_kill signature of param process_id at testdata/phprocksyd/Phprocksyd.php:438 $result = posix_kill($pid, SIGTERM); ^^^^ WARNING invalidDocblock: Malformed @param $stream_id tag (maybe type is missing?) at testdata/phprocksyd/Phprocksyd.php:443 @@ -109,13 +109,13 @@ WARNING invalidDocblock: Malformed @param $req tag (maybe type is missing?) at t WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:481 exit(0); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function explode signature of param string when calling function \microtime at testdata/phprocksyd/Phprocksyd.php:473 +WARNING notSafeCall: potentially not safe call in function explode signature of param string when calling function \microtime at testdata/phprocksyd/Phprocksyd.php:473 $seed = floor(explode(" ", microtime())[0] * 1e6); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function srand signature of param seed at testdata/phprocksyd/Phprocksyd.php:474 +WARNING notSafeCall: potentially not safe call in function srand signature of param seed at testdata/phprocksyd/Phprocksyd.php:474 srand($seed); ^^^^^ -WARNING notSafetyCall: potential not safety call in function mt_srand signature of param seed at testdata/phprocksyd/Phprocksyd.php:475 +WARNING notSafeCall: potentially not safe call in function mt_srand signature of param seed at testdata/phprocksyd/Phprocksyd.php:475 mt_srand($seed); ^^^^^ ERROR undefinedMethod: Call to undefined method {mixed}->run() at testdata/phprocksyd/Phprocksyd.php:479 @@ -127,34 +127,34 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:557 exit(1); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_read_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:560 +WARNING notSafeCall: potentially not safe call in function stream_set_read_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:560 stream_set_read_buffer($fp, 0); ^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_write_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:561 +WARNING notSafeCall: potentially not safe call in function stream_set_write_buffer signature of param stream at testdata/phprocksyd/Phprocksyd.php:561 stream_set_write_buffer($fp, 0); ^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_blocking signature of param stream at testdata/phprocksyd/Phprocksyd.php:562 +WARNING notSafeCall: potentially not safe call in function stream_set_blocking signature of param stream at testdata/phprocksyd/Phprocksyd.php:562 stream_set_blocking($fp, 0); ^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_timeout signature of param stream at testdata/phprocksyd/Phprocksyd.php:563 +WARNING notSafeCall: potentially not safe call in function stream_set_timeout signature of param stream at testdata/phprocksyd/Phprocksyd.php:563 stream_set_timeout($fp, self::CONN_TIMEOUT); ^^^ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:590 exit(0); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function readdir signature of param dir_handle at testdata/phprocksyd/Phprocksyd.php:598 +WARNING notSafeCall: potentially not safe call in function readdir signature of param dir_handle at testdata/phprocksyd/Phprocksyd.php:598 while (false !== ($file = readdir($dh))) { ^^^ -WARNING notSafetyCall: potential not safety call in function fclose signature of param stream when calling function \fopen at testdata/phprocksyd/Phprocksyd.php:605 +WARNING notSafeCall: potentially not safe call in function fclose signature of param stream when calling function \fopen at testdata/phprocksyd/Phprocksyd.php:605 fclose(fopen("php://fd/" . $fd, 'r+')); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:619 exit(1); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function unserialize signature of param data at testdata/phprocksyd/Phprocksyd.php:638 +WARNING notSafeCall: potentially not safe call in function unserialize signature of param data at testdata/phprocksyd/Phprocksyd.php:638 $res = unserialize($contents); ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function explode signature of param string at testdata/phprocksyd/Phprocksyd.php:667 +WARNING notSafeCall: potentially not safe call in function explode signature of param string at testdata/phprocksyd/Phprocksyd.php:667 $parts = explode(' ', $contents); ^^^^^^^^^ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Phprocksyd.php:685 @@ -166,25 +166,25 @@ WARNING useExitOrDie: Don't use the 'exit' function at testdata/phprocksyd/Simpl WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function stream_socket_accept signature of param socket at testdata/phprocksyd/Simple.php:65 $client = stream_socket_accept($server, 1, $peername); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_read_buffer signature of param stream at testdata/phprocksyd/Simple.php:72 +WARNING notSafeCall: potentially not safe call in function stream_set_read_buffer signature of param stream at testdata/phprocksyd/Simple.php:72 stream_set_read_buffer($client, 0); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_write_buffer signature of param stream at testdata/phprocksyd/Simple.php:73 +WARNING notSafeCall: potentially not safe call in function stream_set_write_buffer signature of param stream at testdata/phprocksyd/Simple.php:73 stream_set_write_buffer($client, 0); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_blocking signature of param stream at testdata/phprocksyd/Simple.php:74 +WARNING notSafeCall: potentially not safe call in function stream_set_blocking signature of param stream at testdata/phprocksyd/Simple.php:74 stream_set_blocking($client, 0); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function stream_set_timeout signature of param stream at testdata/phprocksyd/Simple.php:75 +WARNING notSafeCall: potentially not safe call in function stream_set_timeout signature of param stream at testdata/phprocksyd/Simple.php:75 stream_set_timeout($client, 1); ^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rtrim signature of param string at testdata/phprocksyd/Simple.php:116 $res = json_decode(rtrim($req), true); ^^^^ -WARNING notSafetyCall: potential not safety call in function fwrite signature of param data when calling function \substr at testdata/phprocksyd/Simple.php:132 +WARNING notSafeCall: potentially not safe call in function fwrite signature of param data when calling function \substr at testdata/phprocksyd/Simple.php:132 $wrote = fwrite($this->streams[$stream_id], substr($this->write_buf[$stream_id], 0, 65536)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param offset at testdata/phprocksyd/Simple.php:146 +WARNING notSafeCall: potentially not safe call in function substr signature of param offset at testdata/phprocksyd/Simple.php:146 $this->write_buf[$stream_id] = substr($this->write_buf[$stream_id], $wrote); ^^^^^^ ERROR constCase: Constant 'NULL' should be used in lower case as 'null' at testdata/phprocksyd/Simple.php:158 diff --git a/src/tests/golden/testdata/qrcode/golden.txt b/src/tests/golden/testdata/qrcode/golden.txt index 0c828bc3..d91b856d 100644 --- a/src/tests/golden/testdata/qrcode/golden.txt +++ b/src/tests/golden/testdata/qrcode/golden.txt @@ -1,10 +1,10 @@ MAYBE missingPhpdoc: Missing PHPDoc for \QRCode::output_image public method at testdata/qrcode/qrcode.php:45 public function output_image() { ^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function imagepng signature of param image at testdata/qrcode/qrcode.php:49 +WARNING notSafeCall: potentially not safe call in function imagepng signature of param image at testdata/qrcode/qrcode.php:49 imagepng($image); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function imagedestroy signature of param image at testdata/qrcode/qrcode.php:50 +WARNING notSafeCall: potentially not safe call in function imagedestroy signature of param image at testdata/qrcode/qrcode.php:50 imagedestroy($image); ^^^^^^ MAYBE missingPhpdoc: Missing PHPDoc for \QRCode::render_image public method at testdata/qrcode/qrcode.php:53 @@ -16,16 +16,16 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function imagecreatetruecolor signature of param height at testdata/qrcode/qrcode.php:56 $image = imagecreatetruecolor($width, $height); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function imagesavealpha signature of param image at testdata/qrcode/qrcode.php:57 +WARNING notSafeCall: potentially not safe call in function imagesavealpha signature of param image at testdata/qrcode/qrcode.php:57 imagesavealpha($image, true); ^^^^^^ MAYBE ternarySimplify: Could rewrite as `$this->options['bc'] ?? 'FFFFFF'` at testdata/qrcode/qrcode.php:59 $bgcolor = (isset($this->options['bc']) ? $this->options['bc'] : 'FFFFFF'); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function imagefill signature of param image at testdata/qrcode/qrcode.php:61 +WARNING notSafeCall: potentially not safe call in function imagefill signature of param image at testdata/qrcode/qrcode.php:61 imagefill($image, 0, 0, $bgcolor); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function imagefill signature of param color at testdata/qrcode/qrcode.php:61 +WARNING notSafeCall: potentially not safe call in function imagefill signature of param color at testdata/qrcode/qrcode.php:61 imagefill($image, 0, 0, $bgcolor); ^^^^^^^^ MAYBE ternarySimplify: Could rewrite as `$this->options['fc'] ?? '000000'` at testdata/qrcode/qrcode.php:63 @@ -34,31 +34,31 @@ MAYBE ternarySimplify: Could rewrite as `$this->options['fc'] ?? '000000'` at WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function floor signature of param num at testdata/qrcode/qrcode.php:72 $scale = (($scale > 1) ? floor($scale) : 1); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function imagefilledrectangle signature of param image at testdata/qrcode/qrcode.php:93 +WARNING notSafeCall: potentially not safe call in function imagefilledrectangle signature of param image at testdata/qrcode/qrcode.php:93 imagefilledrectangle($image, $rx, $ry, $rx + $rw - 1, $ry + $rh - 1, $mc); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function imagefilledrectangle signature of param x1 at testdata/qrcode/qrcode.php:93 +WARNING notSafeCall: potentially not safe call in function imagefilledrectangle signature of param x1 at testdata/qrcode/qrcode.php:93 imagefilledrectangle($image, $rx, $ry, $rx + $rw - 1, $ry + $rh - 1, $mc); ^^^ -WARNING notSafetyCall: potential not safety call in function imagefilledrectangle signature of param y1 at testdata/qrcode/qrcode.php:93 +WARNING notSafeCall: potentially not safe call in function imagefilledrectangle signature of param y1 at testdata/qrcode/qrcode.php:93 imagefilledrectangle($image, $rx, $ry, $rx + $rw - 1, $ry + $rh - 1, $mc); ^^^ -WARNING notSafetyCall: potential not safety call in function imagefilledrectangle signature of param color at testdata/qrcode/qrcode.php:93 +WARNING notSafeCall: potentially not safe call in function imagefilledrectangle signature of param color at testdata/qrcode/qrcode.php:93 imagefilledrectangle($image, $rx, $ry, $rx + $rw - 1, $ry + $rh - 1, $mc); ^^^ -WARNING notSafetyCall: potential not safety call in function hexdec signature of param hex_string when calling function \substr at testdata/qrcode/qrcode.php:134 +WARNING notSafeCall: potentially not safe call in function hexdec signature of param hex_string when calling function \substr at testdata/qrcode/qrcode.php:134 $r = hexdec(substr($color, 0, 2)); ^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:134 $r = hexdec(substr($color, 0, 2)); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function hexdec signature of param hex_string when calling function \substr at testdata/qrcode/qrcode.php:135 +WARNING notSafeCall: potentially not safe call in function hexdec signature of param hex_string when calling function \substr at testdata/qrcode/qrcode.php:135 $g = hexdec(substr($color, 2, 2)); ^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:135 $g = hexdec(substr($color, 2, 2)); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function hexdec signature of param hex_string when calling function \substr at testdata/qrcode/qrcode.php:136 +WARNING notSafeCall: potentially not safe call in function hexdec signature of param hex_string when calling function \substr at testdata/qrcode/qrcode.php:136 $b = hexdec(substr($color, 4, 2)); ^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:136 @@ -67,13 +67,13 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function imagecolorallocate signature of param image at testdata/qrcode/qrcode.php:137 return imagecolorallocate($image, $r, $g, $b); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function imagecolorallocate signature of param red at testdata/qrcode/qrcode.php:137 +WARNING notSafeCall: potentially not safe call in function imagecolorallocate signature of param red at testdata/qrcode/qrcode.php:137 return imagecolorallocate($image, $r, $g, $b); ^^ -WARNING notSafetyCall: potential not safety call in function imagecolorallocate signature of param green at testdata/qrcode/qrcode.php:137 +WARNING notSafeCall: potentially not safe call in function imagecolorallocate signature of param green at testdata/qrcode/qrcode.php:137 return imagecolorallocate($image, $r, $g, $b); ^^ -WARNING notSafetyCall: potential not safety call in function imagecolorallocate signature of param blue at testdata/qrcode/qrcode.php:137 +WARNING notSafeCall: potentially not safe call in function imagecolorallocate signature of param blue at testdata/qrcode/qrcode.php:137 return imagecolorallocate($image, $r, $g, $b); ^^ WARNING notNullSafetyFunctionArgumentFunctionCall: not null safety call in function strtolower signature of param string when calling function \preg_replace at testdata/qrcode/qrcode.php:143 @@ -124,7 +124,7 @@ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condit WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:316 $group = substr($data, $i, 3); ^^^^^ -WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:317 +WARNING notSafeCall: potentially not safe call in function strlen signature of param string at testdata/qrcode/qrcode.php:317 switch (strlen($group)) { ^^^^^^ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testdata/qrcode/qrcode.php:318 @@ -151,28 +151,28 @@ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condit WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:359 $group = substr($data, $i, 2); ^^^^^ -WARNING notSafetyCall: potential not safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:360 +WARNING notSafeCall: potentially not safe call in function strlen signature of param string at testdata/qrcode/qrcode.php:360 if (strlen($group) > 1) { ^^^^^^ -WARNING notSafetyCall: potential not safety call in function strpos signature of param needle when calling function \substr at testdata/qrcode/qrcode.php:361 +WARNING notSafeCall: potentially not safe call in function strpos signature of param needle when calling function \substr at testdata/qrcode/qrcode.php:361 $c1 = strpos($alphabet, substr($group, 0, 1)); ^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/qrcode/qrcode.php:361 +WARNING notSafeCall: potentially not safe call in function substr signature of param string at testdata/qrcode/qrcode.php:361 $c1 = strpos($alphabet, substr($group, 0, 1)); ^^^^^^ MAYBE callSimplify: Could simplify to $group[0] at testdata/qrcode/qrcode.php:361 $c1 = strpos($alphabet, substr($group, 0, 1)); ^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strpos signature of param needle when calling function \substr at testdata/qrcode/qrcode.php:362 +WARNING notSafeCall: potentially not safe call in function strpos signature of param needle when calling function \substr at testdata/qrcode/qrcode.php:362 $c2 = strpos($alphabet, substr($group, 1, 1)); ^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/qrcode/qrcode.php:362 +WARNING notSafeCall: potentially not safe call in function substr signature of param string at testdata/qrcode/qrcode.php:362 $c2 = strpos($alphabet, substr($group, 1, 1)); ^^^^^^ MAYBE callSimplify: Could simplify to $group[1] at testdata/qrcode/qrcode.php:362 $c2 = strpos($alphabet, substr($group, 1, 1)); ^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function strpos signature of param needle at testdata/qrcode/qrcode.php:376 +WARNING notSafeCall: potentially not safe call in function strpos signature of param needle at testdata/qrcode/qrcode.php:376 $ch = strpos($alphabet, $group); ^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function strlen signature of param string at testdata/qrcode/qrcode.php:390 @@ -184,7 +184,7 @@ WARNING caseBreak: Add break or '// fallthrough' to the end of the case at testd WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/qrcode/qrcode.php:391 switch ($version_group) { ^ -WARNING notSafetyCall: potential not safety call in function ord signature of param character when calling function \substr at testdata/qrcode/qrcode.php:413 +WARNING notSafeCall: potentially not safe call in function ord signature of param character when calling function \substr at testdata/qrcode/qrcode.php:413 $ch = ord(substr($data, $i, 1)); ^^^^^^^^^^^^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:413 @@ -208,25 +208,25 @@ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condit WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function substr signature of param string at testdata/qrcode/qrcode.php:447 $group = substr($data, $i, 2); ^^^^^ -WARNING notSafetyCall: potential not safety call in function ord signature of param character when calling function \substr at testdata/qrcode/qrcode.php:448 +WARNING notSafeCall: potentially not safe call in function ord signature of param character when calling function \substr at testdata/qrcode/qrcode.php:448 $c1 = ord(substr($group, 0, 1)); ^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/qrcode/qrcode.php:448 +WARNING notSafeCall: potentially not safe call in function substr signature of param string at testdata/qrcode/qrcode.php:448 $c1 = ord(substr($group, 0, 1)); ^^^^^^ MAYBE callSimplify: Could simplify to $group[0] at testdata/qrcode/qrcode.php:448 $c1 = ord(substr($group, 0, 1)); ^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function ord signature of param character when calling function \substr at testdata/qrcode/qrcode.php:449 +WARNING notSafeCall: potentially not safe call in function ord signature of param character when calling function \substr at testdata/qrcode/qrcode.php:449 $c2 = ord(substr($group, 1, 1)); ^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function substr signature of param string at testdata/qrcode/qrcode.php:449 +WARNING notSafeCall: potentially not safe call in function substr signature of param string at testdata/qrcode/qrcode.php:449 $c2 = ord(substr($group, 1, 1)); ^^^^^^ MAYBE callSimplify: Could simplify to $group[1] at testdata/qrcode/qrcode.php:449 $c2 = ord(substr($group, 1, 1)); ^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function array_slice signature of param offset at testdata/qrcode/qrcode.php:520 +WARNING notSafeCall: potentially not safe call in function array_slice signature of param offset at testdata/qrcode/qrcode.php:520 $blocks[] = array_slice($data, $offset, $length); ^^^^^^^ WARNING switchDefault: Add 'default' branch to avoid unexpected unhandled condition values at testdata/qrcode/qrcode.php:697 diff --git a/src/tests/golden/testdata/twitter-api-php/golden.txt b/src/tests/golden/testdata/twitter-api-php/golden.txt index 633a6101..bed316d4 100644 --- a/src/tests/golden/testdata/twitter-api-php/golden.txt +++ b/src/tests/golden/testdata/twitter-api-php/golden.txt @@ -19,16 +19,16 @@ WARNING strictCmp: 3rd argument of in_array must be true when comparing strings MAYBE trailingComma: Last element in a multi-line array should have a trailing comma at testdata/twitter-api-php/TwitterAPIExchange.php:223 'oauth_version' => '1.0' ^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter string of function urldecode at testdata/twitter-api-php/TwitterAPIExchange.php:239 +WARNING notSafeCall: potentially not safe array access in parameter string of function urldecode at testdata/twitter-api-php/TwitterAPIExchange.php:239 $oauth[$split[0]] = urldecode($split[1]); ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:253 +WARNING notSafeCall: potentially not safe call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:253 $composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret); ^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:253 +WARNING notSafeCall: potentially not safe call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:253 $composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret); ^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function base64_encode signature of param string when calling function \hash_hmac at testdata/twitter-api-php/TwitterAPIExchange.php:254 +WARNING notSafeCall: potentially not safe call in function base64_encode signature of param string when calling function \hash_hmac at testdata/twitter-api-php/TwitterAPIExchange.php:254 $oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAYBE invalidDocblockType: Use bool type instead of boolean at testdata/twitter-api-php/TwitterAPIExchange.php:267 @@ -37,28 +37,28 @@ MAYBE invalidDocblockType: Use bool type instead of boolean at testdata/twitte WARNING strictCmp: 3rd argument of in_array must be true when comparing strings at testdata/twitter-api-php/TwitterAPIExchange.php:286 if (in_array(strtolower($this->requestMethod), array('put', 'delete'))) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function curl_setopt_array signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:312 +WARNING notSafeCall: potentially not safe call in function curl_setopt_array signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:312 curl_setopt_array($feed, $options); ^^^^^ -WARNING notSafetyCall: potential not safety call in function curl_exec signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:313 +WARNING notSafeCall: potentially not safe call in function curl_exec signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:313 $json = curl_exec($feed); ^^^^^ -WARNING notSafetyCall: potential not safety call in function curl_getinfo signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:315 +WARNING notSafeCall: potentially not safe call in function curl_getinfo signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:315 $this->httpStatusCode = curl_getinfo($feed, CURLINFO_HTTP_CODE); ^^^^^ -WARNING notSafetyCall: potential not safety call in function curl_error signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:317 +WARNING notSafeCall: potentially not safe call in function curl_error signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:317 if (($error = curl_error($feed)) !== '') ^^^^^ -WARNING notSafetyCall: potential not safety call in function curl_error signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:317 +WARNING notSafeCall: potentially not safe call in function curl_error signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:317 if (($error = curl_error($feed)) !== '') ^^^^^ -WARNING notSafetyCall: potential not safety call in function curl_close signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:319 +WARNING notSafeCall: potentially not safe call in function curl_close signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:319 curl_close($feed); ^^^^^ -WARNING notSafetyCall: potential not safety call in function curl_close signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:324 +WARNING notSafeCall: potentially not safe call in function curl_close signature of param handle at testdata/twitter-api-php/TwitterAPIExchange.php:324 curl_close($feed); ^^^^^ -WARNING notSafetyCall: potential not safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:345 +WARNING notSafeCall: potentially not safe call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:345 $return[] = rawurlencode($key) . '=' . rawurlencode($value); ^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function rawurlencode signature of param string at testdata/twitter-api-php/TwitterAPIExchange.php:345 diff --git a/src/tests/golden/testdata/underscore/golden.txt b/src/tests/golden/testdata/underscore/golden.txt index 40326d44..9100bc52 100644 --- a/src/tests/golden/testdata/underscore/golden.txt +++ b/src/tests/golden/testdata/underscore/golden.txt @@ -19,13 +19,13 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:113 $return = array(); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function first signature of param collection at testdata/underscore/underscore.php:139 +WARNING notSafeCall: potentially not safe call in function first signature of param collection at testdata/underscore/underscore.php:139 list($collection, $function_name) = $__->first($args, 2); ^^^^^ -WARNING notSafetyCall: potential not safety call in function map signature of param collection at testdata/underscore/underscore.php:161 +WARNING notSafeCall: potentially not safe call in function map signature of param collection at testdata/underscore/underscore.php:161 if(!is_null($iterator)) $collection = $__->map($collection, $iterator); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function map signature of param collection at testdata/underscore/underscore.php:177 +WARNING notSafeCall: potentially not safe call in function map signature of param collection at testdata/underscore/underscore.php:177 if(!is_null($iterator)) $collection = $__->map($collection, $iterator); ^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:193 @@ -49,25 +49,25 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function array_splice signature of param offset at testdata/underscore/underscore.php:262 return self::_wrap(array_splice($collection, $index)); ^^^^^^ -WARNING notSafetyCall: potential not safety call in function first signature of param n at testdata/underscore/underscore.php:275 +WARNING notSafeCall: potentially not safe call in function first signature of param n at testdata/underscore/underscore.php:275 return self::_wrap($__->first($collection, $first_index)); ^^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:284 if($n === 0) $result = array(); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function rest signature of param collection at testdata/underscore/underscore.php:288 +WARNING notSafeCall: potentially not safe call in function rest signature of param collection at testdata/underscore/underscore.php:288 $result = $__->rest($collection, -$n); ^^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function select signature of param collection at testdata/underscore/underscore.php:302 +WARNING notSafeCall: potentially not safe call in function select signature of param collection at testdata/underscore/underscore.php:302 return self::_wrap($__->select($collection, function($val) { ^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:314 $return = array(); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function flatten signature of param collection at testdata/underscore/underscore.php:319 +WARNING notSafeCall: potentially not safe call in function flatten signature of param collection at testdata/underscore/underscore.php:319 $return = array_merge($return, ($shallow) ? $item : $__->flatten($item)); ^^^^^ -WARNING notSafetyCall: potential not safety call in function rest signature of param collection at testdata/underscore/underscore.php:339 +WARNING notSafeCall: potentially not safe call in function rest signature of param collection at testdata/underscore/underscore.php:339 $removes = $__->rest($args); ^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:360 @@ -79,19 +79,19 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes WARNING unused: Variable $is_sorted is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/underscore/underscore.php:356 list($collection, $is_sorted, $iterator) = self::_wrapArgs(func_get_args(), 3); ^^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function first signature of param collection at testdata/underscore/underscore.php:383 +WARNING notSafeCall: potentially not safe call in function first signature of param collection at testdata/underscore/underscore.php:383 $return = $__->first($arrays); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function rest signature of param collection at testdata/underscore/underscore.php:384 +WARNING notSafeCall: potentially not safe call in function rest signature of param collection at testdata/underscore/underscore.php:384 foreach($__->rest($arrays) as $next) { ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function isArray signature of param item at testdata/underscore/underscore.php:385 +WARNING notSafeCall: potentially not safe call in function isArray signature of param item at testdata/underscore/underscore.php:385 if(!$__->isArray($next)) $next = str_split((string) $next); ^^^^^ -WARNING notSafetyCall: potential not safety call in function isArray signature of param item at testdata/underscore/underscore.php:385 +WARNING notSafeCall: potentially not safe call in function isArray signature of param item at testdata/underscore/underscore.php:385 if(!$__->isArray($next)) $next = str_split((string) $next); ^^^^^ -WARNING notSafetyCall: potential not safety call in function reject signature of param collection at testdata/underscore/underscore.php:441 +WARNING notSafeCall: potentially not safe call in function reject signature of param collection at testdata/underscore/underscore.php:441 $args = $__->reject($args, function($val) { ^^^^^ MAYBE arrayAccess: Array access to non-array type \__|mixed at testdata/underscore/underscore.php:448 @@ -130,10 +130,10 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function range signature of param step at testdata/underscore/underscore.php:458 $results = range($start, $stop, $step); ^^^^^ -WARNING notSafetyCall: potential not safety call in function map signature of param collection at testdata/underscore/underscore.php:475 +WARNING notSafeCall: potentially not safe call in function map signature of param collection at testdata/underscore/underscore.php:475 $num_return_arrays = $__->max($__->map($arrays, function($array) { ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function range signature of param stop at testdata/underscore/underscore.php:478 +WARNING notSafeCall: potentially not safe call in function range signature of param stop at testdata/underscore/underscore.php:478 $return_arrays = $__->range($num_return_arrays); ^^^^^^^^^^^^^^^^^^ MAYBE arrayAccess: Array access to non-array type \__|mixed at testdata/underscore/underscore.php:480 @@ -160,13 +160,13 @@ WARNING unused: Variable $v is unused (use $_ to ignore this inspection or speci MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:497 $results = array(); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function first signature of param collection when calling function \array_keys at testdata/underscore/underscore.php:503 +WARNING notSafeCall: potentially not safe call in function first signature of param collection when calling function \array_keys at testdata/underscore/underscore.php:503 $first_key = $__->first(array_keys($results)); ^^^^^^^^^^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:514 $results = array(); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function first signature of param collection when calling function \array_keys at testdata/underscore/underscore.php:520 +WARNING notSafeCall: potentially not safe call in function first signature of param collection when calling function \array_keys at testdata/underscore/underscore.php:520 $first_key = $__->first(array_keys($results)); ^^^^^^^^^^^^^^^^^^^^ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:529 @@ -184,13 +184,13 @@ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at testdata/underscore/underscore.php:549 if(!array_key_exists($key, $result)) $result[$key] = array(); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function array_slice signature of param offset at testdata/underscore/underscore.php:567 +WARNING notSafeCall: potentially not safe call in function array_slice signature of param offset at testdata/underscore/underscore.php:567 $midpoint_values = array_slice($collection, $midpoint, 1); ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function array_slice signature of param length at testdata/underscore/underscore.php:571 +WARNING notSafeCall: potentially not safe call in function array_slice signature of param length at testdata/underscore/underscore.php:571 $collection = ($calculated_value < $midpoint_calculated_value) ? array_slice($collection, 0, $midpoint, true) : array_slice($collection, $midpoint, null, true); ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function array_slice signature of param offset at testdata/underscore/underscore.php:571 +WARNING notSafeCall: potentially not safe call in function array_slice signature of param offset at testdata/underscore/underscore.php:571 $collection = ($calculated_value < $midpoint_calculated_value) ? array_slice($collection, 0, $midpoint, true) : array_slice($collection, $midpoint, null, true); ^^^^^^^^^ WARNING unused: Variable $__ is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/underscore/underscore.php:561 @@ -199,7 +199,7 @@ WARNING unused: Variable $__ is unused (use $_ to ignore this inspection or spec WARNING unused: Variable $args is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/underscore/underscore.php:615 $args = self::_wrapArgs(func_get_args(), 1); ^^^^^ -WARNING notSafetyCall: potential not safety call in function rest signature of param collection at testdata/underscore/underscore.php:643 +WARNING notSafeCall: potentially not safe call in function rest signature of param collection at testdata/underscore/underscore.php:643 $extensions = $__->rest($args); ^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function get_class signature of param object at testdata/underscore/underscore.php:658 @@ -220,10 +220,10 @@ ERROR undefinedProperty: Property {object}->isEqual does not exist at testdata ERROR undefinedMethod: Call to undefined method {object}->isEqual() at testdata/underscore/underscore.php:724 if(is_object($b) && isset($b->isEqual)) return self::_wrap($b->isEqual($a)); ^^^^^^^ -WARNING notSafetyCall: potential not safety call in function keys signature of param collection at testdata/underscore/underscore.php:731 +WARNING notSafeCall: potentially not safe call in function keys signature of param collection at testdata/underscore/underscore.php:731 $keys_equal = $__->isEqual($__->keys($a), $__->keys($b)); ^^ -WARNING notSafetyCall: potential not safety call in function values signature of param collection at testdata/underscore/underscore.php:732 +WARNING notSafeCall: potentially not safe call in function values signature of param collection at testdata/underscore/underscore.php:732 $values_equal = $__->isEqual($__->values($a), $__->values($b)); ^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function is_nan signature of param num at testdata/underscore/underscore.php:772 @@ -253,13 +253,13 @@ ERROR undefinedProperty: Property {mixed}->_mixins does not exist at testdata/ ERROR undefinedProperty: Property {mixed}->_mixins does not exist at testdata/underscore/underscore.php:853 $mixins =& self::getInstance()->_mixins; ^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter callback of function call_user_func_array at testdata/underscore/underscore.php:854 +WARNING notSafeCall: potentially not safe array access in parameter callback of function call_user_func_array at testdata/underscore/underscore.php:854 return call_user_func_array($mixins[$name], $arguments); ^^^^^^^^^^^^^^ ERROR undefinedProperty: Property {mixed}->_mixins does not exist at testdata/underscore/underscore.php:859 $mixins =& self::getInstance()->_mixins; ^^^^^^^ -WARNING notSafetyCall: potential not safety array access in parameter callback of function call_user_func_array at testdata/underscore/underscore.php:861 +WARNING notSafeCall: potentially not safe array access in parameter callback of function call_user_func_array at testdata/underscore/underscore.php:861 return call_user_func_array($mixins[$name], $arguments); ^^^^^^^^^^^^^^ ERROR undefinedProperty: Property {mixed}->_template_settings does not exist at testdata/underscore/underscore.php:882 @@ -286,7 +286,7 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:920 preg_match_all($ts['interpolate'], $code, $vars, PREG_SET_ORDER); ^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match_all signature of param matches at testdata/underscore/underscore.php:920 +WARNING notSafeCall: potentially not safe call in function preg_match_all signature of param matches at testdata/underscore/underscore.php:920 preg_match_all($ts['interpolate'], $code, $vars, PREG_SET_ORDER); ^^^^^ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access in parameter pattern of function preg_match_all at testdata/underscore/underscore.php:927 @@ -295,7 +295,7 @@ WARNING notNullSafetyFunctionArgumentArrayDimFetch: potential null array access WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function preg_match_all signature of param subject at testdata/underscore/underscore.php:927 preg_match_all($ts['evaluate'], $code, $vars, PREG_SET_ORDER); ^^^^^ -WARNING notSafetyCall: potential not safety call in function preg_match_all signature of param matches at testdata/underscore/underscore.php:927 +WARNING notSafeCall: potentially not safe call in function preg_match_all signature of param matches at testdata/underscore/underscore.php:927 preg_match_all($ts['evaluate'], $code, $vars, PREG_SET_ORDER); ^^^^^ MAYBE deprecated: Call to deprecated function create_function (since: 7.2, reason: Use anonymous functions instead, removed: 8.0) at testdata/underscore/underscore.php:940 @@ -334,10 +334,10 @@ MAYBE arraySyntax: Use the short form '[]' instead of the old 'array()' at tes WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1037 return call_user_func_array($wrapper, $args); ^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1049 +WARNING notSafeCall: potentially not safe call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1049 $args[0] = call_user_func_array($function, $args); ^^^^^^^^^ -WARNING notSafetyCall: potential not safety call in function md5 signature of param string when calling function \mt_rand at testdata/underscore/underscore.php:1062 +WARNING notSafeCall: potentially not safe call in function md5 signature of param string when calling function \mt_rand at testdata/underscore/underscore.php:1062 $key = md5(mt_rand()); ^^^^^^^^^ WARNING notNullSafetyFunctionArgumentVariable: not null safety call in function call_user_func_array signature of param callback at testdata/underscore/underscore.php:1068 From 80aa1522340fa833eef6c2bea17e7ba294d582de Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 15 Apr 2025 04:20:40 +0300 Subject: [PATCH 35/36] review fix --- src/linter/and_walker.go | 4 ++-- src/solver/solver.go | 31 ++++++++++++------------------- src/types/predicates.go | 1 - src/utils/utils.go | 9 --------- 4 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/linter/and_walker.go b/src/linter/and_walker.go index 3655d5ce..9e0bcaba 100644 --- a/src/linter/and_walker.go +++ b/src/linter/and_walker.go @@ -332,8 +332,8 @@ func (a *andWalker) handleTypeCheckCondition(expectedType string, args []ir.Node switch expectedType { case "bool": // For bool: consider possible literal types "bool", "true" and "false" - boolUnion := types.NewMap("bool").Union(types.NewMap("true")).Union(types.NewMap("false")) - intersection := currentType.Intersect(boolUnion) + boolMerge := types.MergeMaps(types.NewMap("bool"), types.NewMap("true"), types.NewMap("false")) + intersection := currentType.Intersect(boolMerge) if intersection.Empty() { // If there is no explicit bool subtype, then the positive branch becomes simply "bool" trueType = types.NewMap("bool") diff --git a/src/solver/solver.go b/src/solver/solver.go index 93c82d5b..c422b735 100644 --- a/src/solver/solver.go +++ b/src/solver/solver.go @@ -511,26 +511,19 @@ func IsMoreSpecific(metaInfo *meta.Info, key1, key2 string) bool { // MergeUnionTypes iteratively merges union types in the Map using specific-ness func MergeUnionTypes(metaInfo *meta.Info, m types.Map) types.Map { - changed := true // Iteratively try to merge the union until no more changes occur - for changed { - changed = false - // Always re-read keys after modifications - keys := m.Keys() - outer: - for i := 0; i < len(keys); i++ { - for j := i + 1; j < len(keys); j++ { - key1 := keys[i] - key2 := keys[j] - if IsMoreSpecific(metaInfo, key1, key2) { - m = m.Erase(key2) - changed = true - break outer - } else if IsMoreSpecific(metaInfo, key2, key1) { - m = m.Erase(key1) - changed = true - break outer - } + // Always re-read keys after modifications + keys := m.Keys() + for i := 0; i < len(keys); i++ { + for j := i + 1; j < len(keys); j++ { + key1 := keys[i] + key2 := keys[j] + if IsMoreSpecific(metaInfo, key1, key2) { + m = m.Erase(key2) + return m + } else if IsMoreSpecific(metaInfo, key2, key1) { + m = m.Erase(key1) + return m } } } diff --git a/src/types/predicates.go b/src/types/predicates.go index 66b390b3..56d330cc 100644 --- a/src/types/predicates.go +++ b/src/types/predicates.go @@ -93,7 +93,6 @@ var scalar = map[string]bool{ "true": true, "false": true, - // "mixed": true, } var aliases = map[string]string{ diff --git a/src/utils/utils.go b/src/utils/utils.go index 3a9ac6de..72db34b8 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -40,15 +40,6 @@ func NameNodeEquals(n ir.Node, s string) bool { } } -func ContainsKey(param string, m map[string]struct{}) bool { - for k := range m { - if strings.Contains(param, k) { - return true - } - } - return false -} - // IsSpecialClassName checks if the passed node is a special class name. func IsSpecialClassName(n ir.Node) bool { name := NameNodeToString(n) From e83321c32160a710d055478d82848e1aa67dc875 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 15 Apr 2025 12:41:36 +0300 Subject: [PATCH 36/36] tests for map.go --- src/types/map_test.go | 126 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/src/types/map_test.go b/src/types/map_test.go index 6762a62d..514d00e2 100644 --- a/src/types/map_test.go +++ b/src/types/map_test.go @@ -47,3 +47,129 @@ func TestEqualNonMatching(t *testing.T) { } } } + +func TestMapUnion(t *testing.T) { + tests := []struct { + a, b Map + expected Map + }{ + { + NewMapFromMap(map[string]struct{}{"int": {}, "string": {}}), + NewMapFromMap(map[string]struct{}{"float": {}}), + NewMapFromMap(map[string]struct{}{"int": {}, "string": {}, "float": {}}), + }, + { + NewMapFromMap(map[string]struct{}{"int": {}}), + NewMapFromMap(map[string]struct{}{"int": {}}), + NewMapFromMap(map[string]struct{}{"int": {}}), + }, + { + NewEmptyMap(0), + NewMapFromMap(map[string]struct{}{"bool": {}}), + NewMapFromMap(map[string]struct{}{"bool": {}}), + }, + { + NewEmptyMap(0), + NewEmptyMap(0), + NewEmptyMap(0), + }, + } + + for _, tt := range tests { + result := tt.a.Union(tt.b) + if !result.Equals(tt.expected) { + t.Errorf("Union failed: %v ∪ %v = %v, expected %v", tt.a, tt.b, result, tt.expected) + } + } +} + +func TestMapIntersect(t *testing.T) { + tests := []struct { + a, b Map + expected Map + }{ + { + NewMapFromMap(map[string]struct{}{"int": {}, "string": {}}), + NewMapFromMap(map[string]struct{}{"int": {}, "float": {}}), + NewMapFromMap(map[string]struct{}{"int": {}}), + }, + { + NewMapFromMap(map[string]struct{}{"bool": {}}), + NewMapFromMap(map[string]struct{}{"int": {}}), + NewEmptyMap(0), + }, + { + NewEmptyMap(0), + NewMapFromMap(map[string]struct{}{"string": {}}), + NewEmptyMap(0), + }, + { + NewMapFromMap(map[string]struct{}{"a": {}, "b": {}}), + NewMapFromMap(map[string]struct{}{"a": {}, "b": {}}), + NewMapFromMap(map[string]struct{}{"a": {}, "b": {}}), + }, + } + + for _, tt := range tests { + result := tt.a.Intersect(tt.b) + if !result.Equals(tt.expected) { + t.Errorf("Intersect failed: %v ∩ %v = %v, expected %v", tt.a, tt.b, result, tt.expected) + } + } +} + +func TestMapIsClass(t *testing.T) { + testCases := []struct { + m Map + expected bool + }{ + // Class + {NewMapFromMap(map[string]struct{}{`\MyClass`: {}}), true}, + + // Array + {NewMapFromMap(map[string]struct{}{`\MyClass[]`: {}}), false}, + + // Shape + {NewMapFromMap(map[string]struct{}{`\shape$foo`: {}}), false}, + + // Closure + {NewMapFromMap(map[string]struct{}{`\Closure$123`: {}}), false}, + + // Scalar + {NewMapFromMap(map[string]struct{}{"int": {}}), false}, + + // Multi types + {NewMapFromMap(map[string]struct{}{`\MyClass`: {}, `int`: {}}), false}, + } + + for _, tc := range testCases { + if got := tc.m.IsClass(); got != tc.expected { + t.Errorf("IsClass() = %v, want %v for %v", got, tc.expected, tc.m) + } + } +} + +func TestMapIsBoolean(t *testing.T) { + testCases := []struct { + m Map + expected bool + }{ + {NewMapFromMap(map[string]struct{}{"bool": {}}), true}, + + {NewMapFromMap(map[string]struct{}{"0400bool": {}}), true}, + + {NewMapFromMap(map[string]struct{}{"true": {}}), true}, + {NewMapFromMap(map[string]struct{}{"false": {}}), true}, + + {NewMapFromMap(map[string]struct{}{"int": {}}), false}, + {NewMapFromMap(map[string]struct{}{`\MyClass`: {}}), false}, + + {NewMapFromMap(map[string]struct{}{"bool": {}, "int": {}}), false}, + } + + for _, tc := range testCases { + if got := tc.m.IsBoolean(); got != tc.expected { + t.Errorf("IsBoolean() = %v, want %v for %v", got, tc.expected, tc.m) + } + } +}