 bf27481efd
			
		
	
	
		bf27481efd
		
			
		
	
	
	
	
		
			
			full diff: https://github.com/dominikh/go-tools/compare/2019.2.3...2020.1.3 Also updates tests to accomodate updated rules: --- FAIL: TestSourcesFromTestdataWithIssuesDir/staticcheck.go (0.43s) linters_test.go:137: [run --disable-all --print-issued-lines=false --print-linter-name=false --out-format=line-number --max-same-issues=10 -Estaticcheck --no-config testdata/staticcheck.go] linters_test.go:33: Error Trace: linters_test.go:33 linters_test.go:138 linters_test.go:53 Error: Received unexpected error: staticcheck.go:11: no match for `self-assignment of x to x` vs ["SA4006: this value of `x` is never used"] in: staticcheck.go:11:2: SA4006: this value of `x` is never used unmatched errors staticcheck.go:11:2: SA4006: this value of `x` is never used Test: TestSourcesFromTestdataWithIssuesDir/staticcheck.go Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
		
			
				
	
	
		
			243 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package pattern
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"go/ast"
 | |
| 	"go/token"
 | |
| 	"go/types"
 | |
| 	"reflect"
 | |
| )
 | |
| 
 | |
| var astTypes = map[string]reflect.Type{
 | |
| 	"Ellipsis":       reflect.TypeOf(ast.Ellipsis{}),
 | |
| 	"RangeStmt":      reflect.TypeOf(ast.RangeStmt{}),
 | |
| 	"AssignStmt":     reflect.TypeOf(ast.AssignStmt{}),
 | |
| 	"IndexExpr":      reflect.TypeOf(ast.IndexExpr{}),
 | |
| 	"Ident":          reflect.TypeOf(ast.Ident{}),
 | |
| 	"ValueSpec":      reflect.TypeOf(ast.ValueSpec{}),
 | |
| 	"GenDecl":        reflect.TypeOf(ast.GenDecl{}),
 | |
| 	"BinaryExpr":     reflect.TypeOf(ast.BinaryExpr{}),
 | |
| 	"ForStmt":        reflect.TypeOf(ast.ForStmt{}),
 | |
| 	"ArrayType":      reflect.TypeOf(ast.ArrayType{}),
 | |
| 	"DeferStmt":      reflect.TypeOf(ast.DeferStmt{}),
 | |
| 	"MapType":        reflect.TypeOf(ast.MapType{}),
 | |
| 	"ReturnStmt":     reflect.TypeOf(ast.ReturnStmt{}),
 | |
| 	"SliceExpr":      reflect.TypeOf(ast.SliceExpr{}),
 | |
| 	"StarExpr":       reflect.TypeOf(ast.StarExpr{}),
 | |
| 	"UnaryExpr":      reflect.TypeOf(ast.UnaryExpr{}),
 | |
| 	"SendStmt":       reflect.TypeOf(ast.SendStmt{}),
 | |
| 	"SelectStmt":     reflect.TypeOf(ast.SelectStmt{}),
 | |
| 	"ImportSpec":     reflect.TypeOf(ast.ImportSpec{}),
 | |
| 	"IfStmt":         reflect.TypeOf(ast.IfStmt{}),
 | |
| 	"GoStmt":         reflect.TypeOf(ast.GoStmt{}),
 | |
| 	"Field":          reflect.TypeOf(ast.Field{}),
 | |
| 	"SelectorExpr":   reflect.TypeOf(ast.SelectorExpr{}),
 | |
| 	"StructType":     reflect.TypeOf(ast.StructType{}),
 | |
| 	"KeyValueExpr":   reflect.TypeOf(ast.KeyValueExpr{}),
 | |
| 	"FuncType":       reflect.TypeOf(ast.FuncType{}),
 | |
| 	"FuncLit":        reflect.TypeOf(ast.FuncLit{}),
 | |
| 	"FuncDecl":       reflect.TypeOf(ast.FuncDecl{}),
 | |
| 	"ChanType":       reflect.TypeOf(ast.ChanType{}),
 | |
| 	"CallExpr":       reflect.TypeOf(ast.CallExpr{}),
 | |
| 	"CaseClause":     reflect.TypeOf(ast.CaseClause{}),
 | |
| 	"CommClause":     reflect.TypeOf(ast.CommClause{}),
 | |
| 	"CompositeLit":   reflect.TypeOf(ast.CompositeLit{}),
 | |
| 	"EmptyStmt":      reflect.TypeOf(ast.EmptyStmt{}),
 | |
| 	"SwitchStmt":     reflect.TypeOf(ast.SwitchStmt{}),
 | |
| 	"TypeSwitchStmt": reflect.TypeOf(ast.TypeSwitchStmt{}),
 | |
| 	"TypeAssertExpr": reflect.TypeOf(ast.TypeAssertExpr{}),
 | |
| 	"TypeSpec":       reflect.TypeOf(ast.TypeSpec{}),
 | |
| 	"InterfaceType":  reflect.TypeOf(ast.InterfaceType{}),
 | |
| 	"BranchStmt":     reflect.TypeOf(ast.BranchStmt{}),
 | |
| 	"IncDecStmt":     reflect.TypeOf(ast.IncDecStmt{}),
 | |
| 	"BasicLit":       reflect.TypeOf(ast.BasicLit{}),
 | |
| }
 | |
| 
 | |
| func ASTToNode(node interface{}) Node {
 | |
| 	switch node := node.(type) {
 | |
| 	case *ast.File:
 | |
| 		panic("cannot convert *ast.File to Node")
 | |
| 	case nil:
 | |
| 		return Nil{}
 | |
| 	case string:
 | |
| 		return String(node)
 | |
| 	case token.Token:
 | |
| 		return Token(node)
 | |
| 	case *ast.ExprStmt:
 | |
| 		return ASTToNode(node.X)
 | |
| 	case *ast.BlockStmt:
 | |
| 		if node == nil {
 | |
| 			return Nil{}
 | |
| 		}
 | |
| 		return ASTToNode(node.List)
 | |
| 	case *ast.FieldList:
 | |
| 		if node == nil {
 | |
| 			return Nil{}
 | |
| 		}
 | |
| 		return ASTToNode(node.List)
 | |
| 	case *ast.BasicLit:
 | |
| 		if node == nil {
 | |
| 			return Nil{}
 | |
| 		}
 | |
| 	case *ast.ParenExpr:
 | |
| 		return ASTToNode(node.X)
 | |
| 	}
 | |
| 
 | |
| 	if node, ok := node.(ast.Node); ok {
 | |
| 		name := reflect.TypeOf(node).Elem().Name()
 | |
| 		T, ok := structNodes[name]
 | |
| 		if !ok {
 | |
| 			panic(fmt.Sprintf("internal error: unhandled type %T", node))
 | |
| 		}
 | |
| 
 | |
| 		if reflect.ValueOf(node).IsNil() {
 | |
| 			return Nil{}
 | |
| 		}
 | |
| 		v := reflect.ValueOf(node).Elem()
 | |
| 		objs := make([]Node, T.NumField())
 | |
| 		for i := 0; i < T.NumField(); i++ {
 | |
| 			f := v.FieldByName(T.Field(i).Name)
 | |
| 			objs[i] = ASTToNode(f.Interface())
 | |
| 		}
 | |
| 
 | |
| 		n, err := populateNode(name, objs, false)
 | |
| 		if err != nil {
 | |
| 			panic(fmt.Sprintf("internal error: %s", err))
 | |
| 		}
 | |
| 		return n
 | |
| 	}
 | |
| 
 | |
| 	s := reflect.ValueOf(node)
 | |
| 	if s.Kind() == reflect.Slice {
 | |
| 		if s.Len() == 0 {
 | |
| 			return List{}
 | |
| 		}
 | |
| 		if s.Len() == 1 {
 | |
| 			return ASTToNode(s.Index(0).Interface())
 | |
| 		}
 | |
| 
 | |
| 		tail := List{}
 | |
| 		for i := s.Len() - 1; i >= 0; i-- {
 | |
| 			head := ASTToNode(s.Index(i).Interface())
 | |
| 			l := List{
 | |
| 				Head: head,
 | |
| 				Tail: tail,
 | |
| 			}
 | |
| 			tail = l
 | |
| 		}
 | |
| 		return tail
 | |
| 	}
 | |
| 
 | |
| 	panic(fmt.Sprintf("internal error: unhandled type %T", node))
 | |
| }
 | |
| 
 | |
| func NodeToAST(node Node, state State) interface{} {
 | |
| 	switch node := node.(type) {
 | |
| 	case Binding:
 | |
| 		v, ok := state[node.Name]
 | |
| 		if !ok {
 | |
| 			// really we want to return an error here
 | |
| 			panic("XXX")
 | |
| 		}
 | |
| 		switch v := v.(type) {
 | |
| 		case types.Object:
 | |
| 			return &ast.Ident{Name: v.Name()}
 | |
| 		default:
 | |
| 			return v
 | |
| 		}
 | |
| 	case Builtin, Any, Object, Function, Not, Or:
 | |
| 		panic("XXX")
 | |
| 	case List:
 | |
| 		if (node == List{}) {
 | |
| 			return []ast.Node{}
 | |
| 		}
 | |
| 		x := []ast.Node{NodeToAST(node.Head, state).(ast.Node)}
 | |
| 		x = append(x, NodeToAST(node.Tail, state).([]ast.Node)...)
 | |
| 		return x
 | |
| 	case Token:
 | |
| 		return token.Token(node)
 | |
| 	case String:
 | |
| 		return string(node)
 | |
| 	case Nil:
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	name := reflect.TypeOf(node).Name()
 | |
| 	T, ok := astTypes[name]
 | |
| 	if !ok {
 | |
| 		panic(fmt.Sprintf("internal error: unhandled type %T", node))
 | |
| 	}
 | |
| 	v := reflect.ValueOf(node)
 | |
| 	out := reflect.New(T)
 | |
| 	for i := 0; i < T.NumField(); i++ {
 | |
| 		fNode := v.FieldByName(T.Field(i).Name)
 | |
| 		if (fNode == reflect.Value{}) {
 | |
| 			continue
 | |
| 		}
 | |
| 		fAST := out.Elem().FieldByName(T.Field(i).Name)
 | |
| 		switch fAST.Type().Kind() {
 | |
| 		case reflect.Slice:
 | |
| 			c := reflect.ValueOf(NodeToAST(fNode.Interface().(Node), state))
 | |
| 			if c.Kind() != reflect.Slice {
 | |
| 				// it's a single node in the pattern, we have to wrap
 | |
| 				// it in a slice
 | |
| 				slice := reflect.MakeSlice(fAST.Type(), 1, 1)
 | |
| 				slice.Index(0).Set(c)
 | |
| 				c = slice
 | |
| 			}
 | |
| 			switch fAST.Interface().(type) {
 | |
| 			case []ast.Node:
 | |
| 				switch cc := c.Interface().(type) {
 | |
| 				case []ast.Node:
 | |
| 					fAST.Set(c)
 | |
| 				case []ast.Expr:
 | |
| 					var slice []ast.Node
 | |
| 					for _, el := range cc {
 | |
| 						slice = append(slice, el)
 | |
| 					}
 | |
| 					fAST.Set(reflect.ValueOf(slice))
 | |
| 				default:
 | |
| 					panic("XXX")
 | |
| 				}
 | |
| 			case []ast.Expr:
 | |
| 				switch cc := c.Interface().(type) {
 | |
| 				case []ast.Node:
 | |
| 					var slice []ast.Expr
 | |
| 					for _, el := range cc {
 | |
| 						slice = append(slice, el.(ast.Expr))
 | |
| 					}
 | |
| 					fAST.Set(reflect.ValueOf(slice))
 | |
| 				case []ast.Expr:
 | |
| 					fAST.Set(c)
 | |
| 				default:
 | |
| 					panic("XXX")
 | |
| 				}
 | |
| 			default:
 | |
| 				panic("XXX")
 | |
| 			}
 | |
| 		case reflect.Int:
 | |
| 			c := reflect.ValueOf(NodeToAST(fNode.Interface().(Node), state))
 | |
| 			switch c.Kind() {
 | |
| 			case reflect.String:
 | |
| 				tok, ok := tokensByString[c.Interface().(string)]
 | |
| 				if !ok {
 | |
| 					// really we want to return an error here
 | |
| 					panic("XXX")
 | |
| 				}
 | |
| 				fAST.SetInt(int64(tok))
 | |
| 			case reflect.Int:
 | |
| 				fAST.Set(c)
 | |
| 			default:
 | |
| 				panic(fmt.Sprintf("internal error: unexpected kind %s", c.Kind()))
 | |
| 			}
 | |
| 		default:
 | |
| 			r := NodeToAST(fNode.Interface().(Node), state)
 | |
| 			if r != nil {
 | |
| 				fAST.Set(reflect.ValueOf(r))
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return out.Interface().(ast.Node)
 | |
| }
 |