Skip to content
This repository was archived by the owner on Dec 30, 2018. It is now read-only.

Commit 7110281

Browse files
committed
Flag uses of deprecated objects
Might interest the folks at golang/lint#238
1 parent 333d80c commit 7110281

File tree

3 files changed

+100
-0
lines changed

3 files changed

+100
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ The following things are currently checked by staticcheck:
6060
| SA1016 | Trapping a signal that cannot be trapped |
6161
| SA1017 | Channels used with signal.Notify should be buffered |
6262
| SA1018 | `strings.Replace` called with n == 0, which does nothing |
63+
| SA1019 | Using a deprecated function, variable, constant or field |
6364
| | |
6465
| **SA2???** | **Concurrency issues** |
6566
| SA2000 | `sync.WaitGroup.Add` called inside the goroutine, leading to a race condition |

lint.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"regexp"
1414
"strconv"
1515
"strings"
16+
"sync"
1617
texttemplate "text/template"
1718
"time"
1819
"unicode/utf8"
@@ -88,6 +89,9 @@ func (d FunctionDescriptions) Merge(fn *ssa.Function, desc Function) {
8889

8990
type Checker struct {
9091
funcDescs FunctionDescriptions
92+
93+
depmu sync.Mutex
94+
deprecatedObjs map[types.Object]string
9195
}
9296

9397
func NewChecker() *Checker {
@@ -115,6 +119,7 @@ func (c *Checker) Funcs() map[string]lint.Func {
115119
"SA1016": c.CheckUntrappableSignal,
116120
"SA1017": c.CheckUnbufferedSignalChan,
117121
"SA1018": c.CheckStringsReplaceZero,
122+
"SA1019": c.CheckDeprecated,
118123

119124
"SA2000": c.CheckWaitgroupAdd,
120125
"SA2001": c.CheckEmptyCriticalSection,
@@ -182,6 +187,7 @@ func terminates(fn *ssa.Function) (ret bool) {
182187

183188
func (c *Checker) Init(prog *lint.Program) {
184189
c.funcDescs = FunctionDescriptions{}
190+
c.deprecatedObjs = map[types.Object]string{}
185191

186192
for fn, desc := range stdlibDescs {
187193
c.funcDescs[fn] = desc
@@ -2646,3 +2652,78 @@ func (c *Checker) CheckPureFunctions(f *lint.File) {
26462652
}
26472653
f.Walk(fn)
26482654
}
2655+
2656+
func (c *Checker) CheckDeprecated(f *lint.File) {
2657+
c.depmu.Lock()
2658+
defer c.depmu.Unlock()
2659+
2660+
fn := func(node ast.Node) bool {
2661+
sel, ok := node.(*ast.SelectorExpr)
2662+
if !ok {
2663+
return true
2664+
}
2665+
obj := f.Pkg.TypesInfo.ObjectOf(sel.Sel)
2666+
if obj.Pkg() == nil {
2667+
return true
2668+
}
2669+
if f.Pkg.PkgInfo.Pkg == obj.Pkg() || obj.Pkg().Path()+"_test" == f.Pkg.PkgInfo.Pkg.Path() {
2670+
// Don't flag stuff in our own package
2671+
return true
2672+
}
2673+
if alt, ok := c.deprecatedObjs[obj]; ok {
2674+
if alt == "" {
2675+
return true
2676+
}
2677+
f.Errorf(sel, "%s is deprecated: %s", f.Render(sel), alt)
2678+
return true
2679+
}
2680+
_, path, _ := f.Program.PathEnclosingInterval(obj.Pos(), obj.Pos())
2681+
if len(path) <= 2 {
2682+
c.deprecatedObjs[obj] = ""
2683+
return true
2684+
}
2685+
var docs []*ast.CommentGroup
2686+
switch n := path[1].(type) {
2687+
case *ast.FuncDecl:
2688+
docs = append(docs, n.Doc)
2689+
case *ast.Field:
2690+
docs = append(docs, n.Doc)
2691+
case *ast.ValueSpec:
2692+
docs = append(docs, n.Doc)
2693+
if len(path) >= 3 {
2694+
if n, ok := path[2].(*ast.GenDecl); ok {
2695+
docs = append(docs, n.Doc)
2696+
}
2697+
}
2698+
case *ast.TypeSpec:
2699+
docs = append(docs, n.Doc)
2700+
if len(path) >= 3 {
2701+
if n, ok := path[2].(*ast.GenDecl); ok {
2702+
docs = append(docs, n.Doc)
2703+
}
2704+
}
2705+
default:
2706+
c.deprecatedObjs[obj] = ""
2707+
return true
2708+
}
2709+
2710+
for _, doc := range docs {
2711+
if doc == nil {
2712+
continue
2713+
}
2714+
parts := strings.Split(doc.Text(), "\n\n")
2715+
last := parts[len(parts)-1]
2716+
if !strings.HasPrefix(last, "Deprecated: ") {
2717+
continue
2718+
}
2719+
alt := last[len("Deprecated: "):]
2720+
alt = strings.Replace(alt, "\n", " ", -1)
2721+
f.Errorf(sel, "%s is deprecated: %s", f.Render(sel), alt)
2722+
c.deprecatedObjs[obj] = alt
2723+
return true
2724+
}
2725+
c.deprecatedObjs[obj] = ""
2726+
return true
2727+
}
2728+
f.Walk(fn)
2729+
}

testdata/CheckDeprecated.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package pkg
2+
3+
import (
4+
"compress/flate"
5+
"net/http"
6+
"os"
7+
"syscall"
8+
)
9+
10+
func fn(err error) {
11+
var r *http.Request
12+
_ = r.Cancel // MATCH /Use the Context and WithContext methods/
13+
_ = syscall.StringByteSlice("") // MATCH /Use ByteSliceFromString instead/
14+
_ = os.SEEK_SET // MATCH /Use io.SeekStart, io.SeekCurrent, and io.SeekEnd/
15+
if err == http.ErrWriteAfterFlush { // MATCH /ErrWriteAfterFlush is no longer used/
16+
}
17+
var _ flate.ReadError // MATCH /No longer returned/
18+
}

0 commit comments

Comments
 (0)