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

Commit

Permalink
Build map of deprecated idents in init phase
Browse files Browse the repository at this point in the history
This removes a mutex. It doesn't yet result in any performance
increases, because we're still doing a lot of work in a single
goroutine, but it will make future improvements easier.

Updates gh-55
  • Loading branch information
dominikh committed Dec 19, 2016
1 parent a184c3e commit 2a4c18b
Showing 1 changed file with 89 additions and 59 deletions.
148 changes: 89 additions & 59 deletions lint.go
Expand Up @@ -11,7 +11,6 @@ import (
"net/http"
"strconv"
"strings"
"sync"
texttemplate "text/template"

"honnef.co/go/lint"
Expand All @@ -20,6 +19,7 @@ import (
"honnef.co/go/staticcheck/vrp"

"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/loader"
)

type Function struct {
Expand Down Expand Up @@ -76,12 +76,9 @@ func (d FunctionDescriptions) Merge(fn *ssa.Function, desc Function) {
}

type Checker struct {
funcDescs FunctionDescriptions

depmu sync.Mutex
funcDescs FunctionDescriptions
deprecatedObjs map[types.Object]string

nodeFns map[ast.Node]*ssa.Function
nodeFns map[ast.Node]*ssa.Function
}

func NewChecker() *Checker {
Expand Down Expand Up @@ -234,8 +231,92 @@ func (c *Checker) Init(prog *lint.Program) {
for _, pkg := range prog.Packages {
for _, f := range pkg.PkgInfo.Files {
ast.Walk(&globalVisitor{c.nodeFns, pkg, f}, f)

ast.Inspect(f, func(node ast.Node) bool {
sel, ok := node.(*ast.SelectorExpr)
if !ok {
return true
}
c.buildDeprecatedMap(pkg, prog.Prog, sel.Sel)
if fn := enclosingFunctionInit(f, sel); fn != nil {
c.buildDeprecatedMap(pkg, prog.Prog, fn.Name)
}
return true
})
}
}
}

func (c *Checker) buildDeprecatedMap(pkg *lint.Pkg, prog *loader.Program, ident *ast.Ident) {
obj := pkg.TypesInfo.ObjectOf(ident)
if obj.Pkg() == nil {
return
}
if _, ok := c.deprecatedObjs[obj]; ok {
return
}

_, path, _ := prog.PathEnclosingInterval(obj.Pos(), obj.Pos())
if len(path) <= 2 {
c.deprecatedObjs[obj] = ""
return
}
var docs []*ast.CommentGroup
switch n := path[1].(type) {
case *ast.FuncDecl:
docs = append(docs, n.Doc)
case *ast.Field:
docs = append(docs, n.Doc)
case *ast.ValueSpec:
docs = append(docs, n.Doc)
if len(path) >= 3 {
if n, ok := path[2].(*ast.GenDecl); ok {
docs = append(docs, n.Doc)
}
}
case *ast.TypeSpec:
docs = append(docs, n.Doc)
if len(path) >= 3 {
if n, ok := path[2].(*ast.GenDecl); ok {
docs = append(docs, n.Doc)
}
}
default:
c.deprecatedObjs[obj] = ""
return
}

for _, doc := range docs {
if doc == nil {
continue
}
parts := strings.Split(doc.Text(), "\n\n")
last := parts[len(parts)-1]
if !strings.HasPrefix(last, "Deprecated: ") {
continue
}
alt := last[len("Deprecated: "):]
alt = strings.Replace(alt, "\n", " ", -1)
c.deprecatedObjs[obj] = alt
return
}
c.deprecatedObjs[obj] = ""
return
}

func enclosingFunctionInit(f *ast.File, node ast.Node) *ast.FuncDecl {
path, _ := astutil.PathEnclosingInterval(f, node.Pos(), node.Pos())
for _, e := range path {
fn, ok := e.(*ast.FuncDecl)
if !ok {
continue
}
if fn.Name == nil {
continue
}
return fn
}
return nil
}

type globalVisitor struct {
Expand Down Expand Up @@ -2607,62 +2688,11 @@ func (c *Checker) isDeprecated(f *lint.File, ident *ast.Ident) (bool, string) {
if obj.Pkg() == nil {
return false, ""
}
if alt, ok := c.deprecatedObjs[obj]; ok {
return alt != "", alt
}

_, path, _ := f.Program.PathEnclosingInterval(obj.Pos(), obj.Pos())
if len(path) <= 2 {
c.deprecatedObjs[obj] = ""
return false, ""
}
var docs []*ast.CommentGroup
switch n := path[1].(type) {
case *ast.FuncDecl:
docs = append(docs, n.Doc)
case *ast.Field:
docs = append(docs, n.Doc)
case *ast.ValueSpec:
docs = append(docs, n.Doc)
if len(path) >= 3 {
if n, ok := path[2].(*ast.GenDecl); ok {
docs = append(docs, n.Doc)
}
}
case *ast.TypeSpec:
docs = append(docs, n.Doc)
if len(path) >= 3 {
if n, ok := path[2].(*ast.GenDecl); ok {
docs = append(docs, n.Doc)
}
}
default:
c.deprecatedObjs[obj] = ""
return false, ""
}

for _, doc := range docs {
if doc == nil {
continue
}
parts := strings.Split(doc.Text(), "\n\n")
last := parts[len(parts)-1]
if !strings.HasPrefix(last, "Deprecated: ") {
continue
}
alt := last[len("Deprecated: "):]
alt = strings.Replace(alt, "\n", " ", -1)
c.deprecatedObjs[obj] = alt
return true, alt
}
c.deprecatedObjs[obj] = ""
return false, ""
alt := c.deprecatedObjs[obj]
return alt != "", alt
}

func (c *Checker) CheckDeprecated(f *lint.File) {
c.depmu.Lock()
defer c.depmu.Unlock()

fn := func(node ast.Node) bool {
sel, ok := node.(*ast.SelectorExpr)
if !ok {
Expand Down

0 comments on commit 2a4c18b

Please sign in to comment.