passes/unusedwrites: Add TODO for how to handle generics.
Adds a TODO to explain how to support generics, e.g. fn._Instantiations() should be included once available.
Refactors the run() function to make this simple in the future.
Updates golang/go#52503
Change-Id: Iec84f9bf200cab1026b19e1962165102be0a85ef
Reviewed-on: https://go-review.googlesource.com/c/tools/+/403355
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Run-TryBot: Guodong Li <guodongli@google.com>
Run-TryBot: Tim King <taking@google.com>
Reviewed-by: Guodong Li <guodongli@google.com>
Auto-Submit: Tim King <taking@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/go/analysis/passes/unusedwrite/unusedwrite.go b/go/analysis/passes/unusedwrite/unusedwrite.go
index 4aad083..9cc45e0 100644
--- a/go/analysis/passes/unusedwrite/unusedwrite.go
+++ b/go/analysis/passes/unusedwrite/unusedwrite.go
@@ -50,40 +50,49 @@
}
func run(pass *analysis.Pass) (interface{}, error) {
- // Check the writes to struct and array objects.
- checkStore := func(store *ssa.Store) {
- // Consider field/index writes to an object whose elements are copied and not shared.
- // MapUpdate is excluded since only the reference of the map is copied.
- switch addr := store.Addr.(type) {
- case *ssa.FieldAddr:
- if isDeadStore(store, addr.X, addr) {
- // Report the bug.
+ ssainput := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA)
+ for _, fn := range ssainput.SrcFuncs {
+ // TODO(taking): Iterate over fn._Instantiations() once exported. If so, have 1 report per Pos().
+ reports := checkStores(fn)
+ for _, store := range reports {
+ switch addr := store.Addr.(type) {
+ case *ssa.FieldAddr:
pass.Reportf(store.Pos(),
"unused write to field %s",
getFieldName(addr.X.Type(), addr.Field))
- }
- case *ssa.IndexAddr:
- if isDeadStore(store, addr.X, addr) {
- // Report the bug.
+ case *ssa.IndexAddr:
pass.Reportf(store.Pos(),
"unused write to array index %s", addr.Index)
}
}
}
+ return nil, nil
+}
- ssainput := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA)
- for _, fn := range ssainput.SrcFuncs {
- // Visit each block. No need to visit fn.Recover.
- for _, blk := range fn.Blocks {
- for _, instr := range blk.Instrs {
- // Identify writes.
- if store, ok := instr.(*ssa.Store); ok {
- checkStore(store)
+// checkStores returns *Stores in fn whose address is written to but never used.
+func checkStores(fn *ssa.Function) []*ssa.Store {
+ var reports []*ssa.Store
+ // Visit each block. No need to visit fn.Recover.
+ for _, blk := range fn.Blocks {
+ for _, instr := range blk.Instrs {
+ // Identify writes.
+ if store, ok := instr.(*ssa.Store); ok {
+ // Consider field/index writes to an object whose elements are copied and not shared.
+ // MapUpdate is excluded since only the reference of the map is copied.
+ switch addr := store.Addr.(type) {
+ case *ssa.FieldAddr:
+ if isDeadStore(store, addr.X, addr) {
+ reports = append(reports, store)
+ }
+ case *ssa.IndexAddr:
+ if isDeadStore(store, addr.X, addr) {
+ reports = append(reports, store)
+ }
}
}
}
}
- return nil, nil
+ return reports
}
// isDeadStore determines whether a field/index write to an object is dead.