mirror of
https://github.com/golang/go
synced 2024-11-11 19:21:37 -07:00
[dev.regabi] cmd/compile: report unused variables during typecheck
Unused variables are a type-checking error, so they should be reported during typecheck rather than walk. One catch is that we only want to report unused-variable errors for functions that type check successfully, but some errors are reported during noding, so we don't have an easy way to detect that currently. As an approximate solution, we simply check if we've reported any errors yet. Passes toolstash -cmp. Change-Id: I9400bfc94312c71d0c908a491e85c16d62224c9c Reviewed-on: https://go-review.googlesource.com/c/go/+/280973 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
parent
fd22df9905
commit
b8fd3440cd
@ -171,6 +171,7 @@ func FuncBody(n *ir.Func) {
|
||||
decldepth = 1
|
||||
errorsBefore := base.Errors()
|
||||
Stmts(n.Body)
|
||||
CheckUnused(n)
|
||||
CheckReturn(n)
|
||||
if base.Errors() > errorsBefore {
|
||||
n.Body.Set(nil) // type errors; do not compile
|
||||
@ -2203,6 +2204,39 @@ func isTermNode(n ir.Node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CheckUnused checks for any declared variables that weren't used.
|
||||
func CheckUnused(fn *ir.Func) {
|
||||
// Only report unused variables if we haven't seen any type-checking
|
||||
// errors yet.
|
||||
if base.Errors() != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Propagate the used flag for typeswitch variables up to the NONAME in its definition.
|
||||
for _, ln := range fn.Dcl {
|
||||
if ln.Op() == ir.ONAME && ln.Class_ == ir.PAUTO && ln.Used() {
|
||||
if guard, ok := ln.Defn.(*ir.TypeSwitchGuard); ok {
|
||||
guard.Used = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, ln := range fn.Dcl {
|
||||
if ln.Op() != ir.ONAME || ln.Class_ != ir.PAUTO || ln.Used() {
|
||||
continue
|
||||
}
|
||||
if defn, ok := ln.Defn.(*ir.TypeSwitchGuard); ok {
|
||||
if defn.Used {
|
||||
continue
|
||||
}
|
||||
base.ErrorfAt(defn.Tag.Pos(), "%v declared but not used", ln.Sym())
|
||||
defn.Used = true // suppress repeats
|
||||
} else {
|
||||
base.ErrorfAt(ln.Pos(), "%v declared but not used", ln.Sym())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckReturn makes sure that fn terminates appropriately.
|
||||
func CheckReturn(fn *ir.Func) {
|
||||
if fn.Type().NumResults() != 0 && len(fn.Body) != 0 {
|
||||
|
@ -37,36 +37,6 @@ func Walk(fn *ir.Func) {
|
||||
|
||||
lno := base.Pos
|
||||
|
||||
// Final typecheck for any unused variables.
|
||||
for i, ln := range fn.Dcl {
|
||||
if ln.Op() == ir.ONAME && (ln.Class_ == ir.PAUTO || ln.Class_ == ir.PAUTOHEAP) {
|
||||
ln = typecheck.AssignExpr(ln).(*ir.Name)
|
||||
fn.Dcl[i] = ln
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate the used flag for typeswitch variables up to the NONAME in its definition.
|
||||
for _, ln := range fn.Dcl {
|
||||
if ln.Op() == ir.ONAME && (ln.Class_ == ir.PAUTO || ln.Class_ == ir.PAUTOHEAP) && ln.Defn != nil && ln.Defn.Op() == ir.OTYPESW && ln.Used() {
|
||||
ln.Defn.(*ir.TypeSwitchGuard).Used = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, ln := range fn.Dcl {
|
||||
if ln.Op() != ir.ONAME || (ln.Class_ != ir.PAUTO && ln.Class_ != ir.PAUTOHEAP) || ln.Sym().Name[0] == '&' || ln.Used() {
|
||||
continue
|
||||
}
|
||||
if defn, ok := ln.Defn.(*ir.TypeSwitchGuard); ok {
|
||||
if defn.Used {
|
||||
continue
|
||||
}
|
||||
base.ErrorfAt(defn.Tag.Pos(), "%v declared but not used", ln.Sym())
|
||||
defn.Used = true // suppress repeats
|
||||
} else {
|
||||
base.ErrorfAt(ln.Pos(), "%v declared but not used", ln.Sym())
|
||||
}
|
||||
}
|
||||
|
||||
base.Pos = lno
|
||||
if base.Errors() > errorsBefore {
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user