Skip to content

Commit 483e5a4

Browse files
committed
added deep chain catching for checkPropertyFetchNullSafety
1 parent e84f894 commit 483e5a4

File tree

1 file changed

+51
-34
lines changed

1 file changed

+51
-34
lines changed

src/linter/block.go

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,51 +1138,68 @@ func (b *blockWalker) checkListExprNullSafety(arg ir.Node, fn meta.FuncInfo, par
11381138
}
11391139
}
11401140

1141+
func (b *blockWalker) getPropertyComputedType(expr *ir.PropertyFetchExpr) (meta.ClassInfo, types.Map) {
1142+
baseCall, ok := expr.Variable.(*ir.SimpleVar)
1143+
if !ok {
1144+
return meta.ClassInfo{}, types.Map{}
1145+
}
1146+
1147+
varInfo, ok := b.ctx.sc.GetVar(baseCall)
1148+
if !ok {
1149+
return meta.ClassInfo{}, types.Map{}
1150+
}
1151+
1152+
classInfo, ok := b.r.ctx.st.Info.GetClass(varInfo.Type.String())
1153+
if !ok {
1154+
return meta.ClassInfo{}, types.Map{}
1155+
}
1156+
1157+
property, ok := expr.Property.(*ir.Identifier)
1158+
if !ok {
1159+
return meta.ClassInfo{}, types.Map{}
1160+
}
1161+
1162+
propertyInfoFromClass := classInfo.Properties[property.Value]
1163+
return classInfo, propertyInfoFromClass.Typ
1164+
}
1165+
11411166
func (b *blockWalker) checkPropertyFetchNullSafety(expr *ir.PropertyFetchExpr, fn meta.FuncInfo, paramIndex int, haveVariadic bool) {
1142-
objVar, ok := expr.Variable.(*ir.SimpleVar)
1167+
// If the left part of the chain is also a property call, we check it recursively
1168+
if nested, ok := expr.Variable.(*ir.PropertyFetchExpr); ok {
1169+
b.checkPropertyFetchNullSafety(nested, fn, paramIndex, haveVariadic)
1170+
}
11431171

1144-
if ok {
1145-
varInfo, _ := b.ctx.sc.GetVar(objVar)
1146-
classInfo, _ := b.r.ctx.st.Info.GetClass(varInfo.Type.String())
1147-
1148-
prp, okPrp := expr.Property.(*ir.Identifier)
1149-
1150-
if okPrp {
1151-
property := classInfo.Properties[prp.Value]
1152-
1153-
isPrpNullable := types.IsTypeNullable(property.Typ)
1154-
if haveVariadic {
1155-
// If the parameter is outside the declared parameters, we check the latter as a variable
1156-
if paramIndex >= len(fn.Params)-1 {
1157-
lastParam := fn.Params[len(fn.Params)-1] // last param (variadic ...args)
1158-
if types.IsTypeMixed(lastParam.Typ) {
1159-
return
1160-
}
1161-
1162-
paramAllowsNull := types.IsTypeNullable(lastParam.Typ)
1163-
if isPrpNullable && !paramAllowsNull {
1164-
b.report(expr, LevelError, "notNullSafety",
1165-
"potential null dereference when accessing property '%s'", prp.Value)
1166-
}
1167-
return
1172+
classInfo, propType := b.getPropertyComputedType(expr)
1173+
if classInfo.Name == "" || propType.Empty() {
1174+
return
1175+
}
11681176

1169-
}
1170-
}
1177+
prp, ok := expr.Property.(*ir.Identifier)
1178+
if !ok {
1179+
return
1180+
}
11711181

1172-
paramAllowsNull := types.IsTypeNullable(fn.Params[paramIndex].Typ)
1182+
isPrpNullable := types.IsTypeNullable(propType)
11731183

1184+
if haveVariadic {
1185+
if paramIndex >= len(fn.Params)-1 {
1186+
lastParam := fn.Params[len(fn.Params)-1]
1187+
if types.IsTypeMixed(lastParam.Typ) {
1188+
return
1189+
}
1190+
paramAllowsNull := types.IsTypeNullable(lastParam.Typ)
11741191
if isPrpNullable && !paramAllowsNull {
11751192
b.report(expr, LevelError, "notNullSafety",
11761193
"potential null dereference when accessing property '%s'", prp.Value)
11771194
}
1178-
1179-
println(classInfo.Name)
1195+
return
11801196
}
1197+
}
11811198

1182-
// TODO: check difficult chains like $a->b->c->d
1183-
/* if nestedProp, ok := expr.Variable.(*ir.PropertyFetchExpr); ok {
1184-
b.checkPropertyFetchNullSafety(nestedProp)
1185-
}*/
1199+
paramAllowsNull := types.IsTypeNullable(fn.Params[paramIndex].Typ)
1200+
if isPrpNullable && !paramAllowsNull {
1201+
b.report(expr, LevelError, "notNullSafety",
1202+
"potential null dereference when accessing property '%s'", prp.Value)
11861203
}
11871204
}
11881205

0 commit comments

Comments
 (0)