@@ -1028,27 +1028,35 @@ func (b *blockWalker) handleIssetDimFetch(e *ir.ArrayDimFetchExpr) {
1028
1028
}
1029
1029
1030
1030
func (b * blockWalker ) checkNullSafetyCallArgsF (args []ir.Node , fn meta.FuncInfo ) {
1031
+ if fn .Params == nil || fn .Name == "" {
1032
+ return
1033
+ }
1034
+ haveVariadic := enoughArgs (args , fn )
1035
+
1031
1036
for i , arg := range args {
1037
+ if arg == nil {
1038
+ continue
1039
+ }
1032
1040
switch a := arg .(* ir.Argument ).Expr .(type ) {
1033
1041
case * ir.SimpleVar :
1034
- b .checkSimpleVarNullSafety (arg , fn , i , a )
1042
+ // b.checkSimpleVarNullSafety(arg, fn, i, a, haveVariadic )
1035
1043
1036
1044
case * ir.ConstFetchExpr :
1037
- b .checkConstFetchNullSafety (arg , fn , i , a )
1045
+ b .checkConstFetchNullSafety (arg , fn , i , a , haveVariadic )
1038
1046
1039
1047
case * ir.ArrayDimFetchExpr :
1040
- b .checkArrayDimFetchNullSafety (arg , fn , i , a )
1048
+ // b.checkArrayDimFetchNullSafety(arg, fn, i, a, haveVariadic )
1041
1049
1042
1050
case * ir.ListExpr :
1043
- b .checkListExprNullSafety (arg , fn , i , a )
1051
+ b .checkListExprNullSafety (arg , fn , i , a , haveVariadic )
1044
1052
1045
1053
case * ir.PropertyFetchExpr :
1046
1054
b .checkPropertyFetchNullSafety (a )
1047
1055
}
1048
1056
}
1049
1057
}
1050
1058
1051
- func (b * blockWalker ) checkSimpleVarNullSafety (arg ir.Node , fn meta.FuncInfo , paramIndex int , variable * ir.SimpleVar ) {
1059
+ func (b * blockWalker ) checkSimpleVarNullSafety (arg ir.Node , fn meta.FuncInfo , paramIndex int , variable * ir.SimpleVar , haveVariadic bool ) {
1052
1060
varInfo , ok := b .ctx .sc .GetVar (variable )
1053
1061
1054
1062
if ! ok {
@@ -1063,18 +1071,38 @@ func (b *blockWalker) checkSimpleVarNullSafety(arg ir.Node, fn meta.FuncInfo, pa
1063
1071
}
1064
1072
}
1065
1073
1066
- func (b * blockWalker ) checkConstFetchNullSafety (arg ir.Node , fn meta.FuncInfo , paramIndex int , constExpr * ir.ConstFetchExpr ) {
1074
+ func (b * blockWalker ) checkConstFetchNullSafety (arg ir.Node , fn meta.FuncInfo , paramIndex int , constExpr * ir.ConstFetchExpr , haveVariadic bool ) {
1067
1075
constVal := constExpr .Constant .Value
1068
1076
isNull := constVal == "null"
1069
1077
1078
+ if haveVariadic {
1079
+ // If the parameter is outside the declared parameters, we check the latter as a variable
1080
+ if paramIndex >= len (fn .Params )- 1 {
1081
+ lastParam := fn .Params [len (fn .Params )- 1 ] // last param (variadic ...args)
1082
+ if types .IsTypeMixed (lastParam .Typ ) {
1083
+ return
1084
+ }
1085
+
1086
+ paramAllowsNull := types .IsTypeNullable (lastParam .Typ )
1087
+ if isNull && ! paramAllowsNull {
1088
+ b .report (arg , LevelError , "notNullSafety" ,
1089
+ "null passed to non-nullable variadic parameter %s in function %s" ,
1090
+ lastParam .Name , fn .Name )
1091
+ }
1092
+ return
1093
+ }
1094
+ }
1095
+
1070
1096
paramAllowsNull := types .IsTypeNullable (fn .Params [paramIndex ].Typ )
1071
1097
if isNull && ! paramAllowsNull {
1072
- b .report (arg , LevelError , "notNullSafety" , "null passed to non-nullable parameter %s in function %s" , fn .Params [paramIndex ].Name , fn .Name )
1098
+ b .report (arg , LevelError , "notNullSafety" ,
1099
+ "null passed to non-nullable parameter %s in function %s" ,
1100
+ fn .Params [paramIndex ].Name , fn .Name )
1073
1101
}
1074
1102
}
1075
1103
1076
1104
// TODO: we don't know type of each element without phpDoc, it will be mixed
1077
- func (b * blockWalker ) checkArrayDimFetchNullSafety (arg ir.Node , fn meta.FuncInfo , paramIndex int , arrayExpr * ir.ArrayDimFetchExpr ) {
1105
+ func (b * blockWalker ) checkArrayDimFetchNullSafety (arg ir.Node , fn meta.FuncInfo , paramIndex int , arrayExpr * ir.ArrayDimFetchExpr , haveVariadic bool ) {
1078
1106
baseVar , ok := arrayExpr .Variable .(* ir.SimpleVar )
1079
1107
if ! ok {
1080
1108
return
@@ -1091,7 +1119,7 @@ func (b *blockWalker) checkArrayDimFetchNullSafety(arg ir.Node, fn meta.FuncInfo
1091
1119
}
1092
1120
1093
1121
// TODO: we don't know type of each element without phpDoc, it will be mixed
1094
- func (b * blockWalker ) checkListExprNullSafety (arg ir.Node , fn meta.FuncInfo , paramIndex int , listExpr * ir.ListExpr ) {
1122
+ func (b * blockWalker ) checkListExprNullSafety (arg ir.Node , fn meta.FuncInfo , paramIndex int , listExpr * ir.ListExpr , haveVariadic bool ) {
1095
1123
for _ , item := range listExpr .Items {
1096
1124
if item == nil {
1097
1125
continue
0 commit comments