diff --git a/assertion/function/assertiontree/parse_expr_producer.go b/assertion/function/assertiontree/parse_expr_producer.go index 3a7db8a5..ea5f32dd 100644 --- a/assertion/function/assertiontree/parse_expr_producer.go +++ b/assertion/function/assertiontree/parse_expr_producer.go @@ -231,7 +231,22 @@ func (r *RootAssertionNode) ParseExprAsProducer(expr ast.Expr, doNotTrack bool) return nil, fldReadProduce() case *ast.CallExpr: - // we delay this check until we're sure we have to make it, as it could be expensive + if r.Pass().TypesInfo.Types[expr.Fun].IsType() { + if len(expr.Args) == 0 { + return nil, nil + } + + if r.Pass().ExprBarsNilness(expr.Fun) { + return nil, nil + } + + return r.ParseExprAsProducer(expr.Args[0], false) + } + + if prod := hook.AssumeReturn(r.Pass(), expr); prod != nil { + return nil, []producer.ParsedProducer{producer.ShallowParsedProducer{Producer: prod}} + } + litArgs := func() bool { for _, expr := range expr.Args { if !r.isStable(expr) { @@ -241,10 +256,6 @@ func (r *RootAssertionNode) ParseExprAsProducer(expr ast.Expr, doNotTrack bool) return true } - if prod := hook.AssumeReturn(r.Pass(), expr); prod != nil { - return nil, []producer.ParsedProducer{producer.ShallowParsedProducer{Producer: prod}} - } - // the cases of a function and method call are different enough here that it would be useless // to try to subsume this switch with funcIdentFromCallExpr switch fun := expr.Fun.(type) { diff --git a/testdata/src/go.uber.org/trustedfunc/type_conversion.go b/testdata/src/go.uber.org/trustedfunc/type_conversion.go new file mode 100644 index 00000000..842f4393 --- /dev/null +++ b/testdata/src/go.uber.org/trustedfunc/type_conversion.go @@ -0,0 +1,56 @@ +// Copyright (c) 2024 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trustedfunc + +type Struct struct { + Field int +} + +type StructPtr *Struct + +func typeConversionBasic() { + var explicit *Struct + explicit = (*Struct)(nil) + _ = explicit.Field // want "deref" + + explicitShort := (*Struct)(nil) + _ = explicitShort.Field // want "deref" + + explicitWithoutParens := StructPtr(nil) + _ = explicitWithoutParens.Field // want "deref" + + var implicit *Struct + implicit = nil + _ = implicit.Field // want "deref" +} + +func typeConversionWithNonNil() { + var s *Struct = &Struct{Field: 42} + explicit := (*Struct)(s) + _ = explicit.Field + + var implicit *Struct + implicit = s + _ = implicit.Field +} + +func typeConversionToNonNilable() { + var i int = 42 + converted := int(i) + _ = converted // Should not report nil dereference + + f := float64(i) + _ = f // Should not report nil dereference +}