diff --git a/go/analysis/passes/modernize/atomictypes.go b/go/analysis/passes/modernize/atomictypes.go
index 6fd618f..382295f 100644
--- a/go/analysis/passes/modernize/atomictypes.go
+++ b/go/analysis/passes/modernize/atomictypes.go
@@ -64,8 +64,9 @@
}
var (
- index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
- info = pass.TypesInfo
+ inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+ index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
+ info = pass.TypesInfo
)
// Gather all candidate variables v appearing
@@ -123,6 +124,14 @@
case *ast.Field: // struct { v int }
names = parent.Names
typ = parent.Type
+ structCursor := def.Parent().Parent().Parent()
+ structType := info.TypeOf(structCursor.Node().(*ast.StructType))
+ if typeSpec, ok := structCursor.Parent().Node().(*ast.TypeSpec); ok {
+ structType = info.Defs[typeSpec.Name].Type()
+ }
+ if hasUnkeyedLiteralOfStruct(inspect, info, structType) {
+ continue
+ }
case *ast.ValueSpec: // var v int
if len(parent.Values) > 0 {
// e.g. var v int = 5
@@ -249,3 +258,37 @@
return nil, nil
}
+
+// hasUnkeyedLiteralOfStruct reports whether the package contains an unkeyed
+// composite literal of the specified struct type. Such literals don't contain
+// identifiers for their fields, so they don't appear in the type index's uses
+// of a field object. Changing a field's type may make them ill-typed.
+func hasUnkeyedLiteralOfStruct(inspect *inspector.Inspector, info *types.Info, structType types.Type) bool {
+ for lit := range inspect.Root().Preorder((*ast.CompositeLit)(nil)) {
+ composite := lit.Node().(*ast.CompositeLit)
+ if len(composite.Elts) == 0 {
+ continue
+ }
+ if _, keyed := composite.Elts[0].(*ast.KeyValueExpr); keyed {
+ continue
+ }
+ if typ := info.TypeOf(composite); typ != nil && identicalStructType(typ, structType) {
+ return true
+ }
+ }
+ return false
+}
+
+// identicalStructType reports whether x and y denote the same struct type,
+// treating instances of the same generic named type as identical for the
+// purpose of this conservative check.
+func identicalStructType(x, y types.Type) bool {
+ x = types.Unalias(x)
+ y = types.Unalias(y)
+ if types.Identical(x, y) {
+ return true
+ }
+ xnamed, xok := x.(*types.Named)
+ ynamed, yok := y.(*types.Named)
+ return xok && yok && xnamed.Origin() == ynamed.Origin()
+}
diff --git a/go/analysis/passes/modernize/testdata/src/atomictypes/atomic.go b/go/analysis/passes/modernize/testdata/src/atomictypes/atomic.go
index f6a825e..5f92c82 100644
--- a/go/analysis/passes/modernize/testdata/src/atomictypes/atomic.go
+++ b/go/analysis/passes/modernize/testdata/src/atomictypes/atomic.go
@@ -9,6 +9,23 @@
x int32 // want "var x int32 may be simplified using atomic.Int32"
}
+type Unkeyed struct {
+ x int32
+}
+
+var _ = Unkeyed{1} // nope: can't assign an int to an atomic.Int32
+var _ = []Unkeyed{{1}} // also detect literals whose type is elided
+
+func unkeyed(s *Unkeyed) {
+ atomic.AddInt32(&s.x, 1)
+}
+
+var unkeyedAnonymous = struct{ x int32 }{1}
+
+func useUnkeyedAnonymous() {
+ atomic.AddInt32(&unkeyedAnonymous.x, 1)
+}
+
type Z struct {
y int64 // want "var y int64 may be simplified using atomic.Int64"
z int64
diff --git a/go/analysis/passes/modernize/testdata/src/atomictypes/atomic.go.golden b/go/analysis/passes/modernize/testdata/src/atomictypes/atomic.go.golden
index 7c995a7..af5d9f9 100644
--- a/go/analysis/passes/modernize/testdata/src/atomictypes/atomic.go.golden
+++ b/go/analysis/passes/modernize/testdata/src/atomictypes/atomic.go.golden
@@ -9,6 +9,23 @@
x atomic.Int32 // want "var x int32 may be simplified using atomic.Int32"
}
+type Unkeyed struct {
+ x int32
+}
+
+var _ = Unkeyed{1} // nope: can't assign an int to an atomic.Int32
+var _ = []Unkeyed{{1}} // also detect literals whose type is elided
+
+func unkeyed(s *Unkeyed) {
+ atomic.AddInt32(&s.x, 1)
+}
+
+var unkeyedAnonymous = struct{ x int32 }{1}
+
+func useUnkeyedAnonymous() {
+ atomic.AddInt32(&unkeyedAnonymous.x, 1)
+}
+
type Z struct {
y atomic.Int64 // want "var y int64 may be simplified using atomic.Int64"
z int64
@@ -51,4 +68,4 @@
}
atomic.AddInt64(&w.z, 1) // nope - cannot fix initial value assignment
return
-}
\ No newline at end of file
+}