@@ -13,6 +13,7 @@ import (
13
13
"regexp"
14
14
"strconv"
15
15
"strings"
16
+ "sync"
16
17
texttemplate "text/template"
17
18
"time"
18
19
"unicode/utf8"
@@ -88,6 +89,9 @@ func (d FunctionDescriptions) Merge(fn *ssa.Function, desc Function) {
88
89
89
90
type Checker struct {
90
91
funcDescs FunctionDescriptions
92
+
93
+ depmu sync.Mutex
94
+ deprecatedObjs map [types.Object ]string
91
95
}
92
96
93
97
func NewChecker () * Checker {
@@ -115,6 +119,7 @@ func (c *Checker) Funcs() map[string]lint.Func {
115
119
"SA1016" : c .CheckUntrappableSignal ,
116
120
"SA1017" : c .CheckUnbufferedSignalChan ,
117
121
"SA1018" : c .CheckStringsReplaceZero ,
122
+ "SA1019" : c .CheckDeprecated ,
118
123
119
124
"SA2000" : c .CheckWaitgroupAdd ,
120
125
"SA2001" : c .CheckEmptyCriticalSection ,
@@ -182,6 +187,7 @@ func terminates(fn *ssa.Function) (ret bool) {
182
187
183
188
func (c * Checker ) Init (prog * lint.Program ) {
184
189
c .funcDescs = FunctionDescriptions {}
190
+ c .deprecatedObjs = map [types.Object ]string {}
185
191
186
192
for fn , desc := range stdlibDescs {
187
193
c .funcDescs [fn ] = desc
@@ -2646,3 +2652,78 @@ func (c *Checker) CheckPureFunctions(f *lint.File) {
2646
2652
}
2647
2653
f .Walk (fn )
2648
2654
}
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
+ }
0 commit comments