github.com/kdevb0x/go@v0.0.0-20180115030120-39687051e9e7/src/cmd/fix/cftype.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"go/ast"
     9  	"go/token"
    10  	"reflect"
    11  	"strings"
    12  )
    13  
    14  func init() {
    15  	register(cftypeFix)
    16  }
    17  
    18  var cftypeFix = fix{
    19  	name:     "cftype",
    20  	date:     "2017-09-27",
    21  	f:        cftypefix,
    22  	desc:     `Fixes initializers of C.CF*Ptr types`,
    23  	disabled: false,
    24  }
    25  
    26  // Old state:
    27  //   type CFTypeRef unsafe.Pointer
    28  // New state:
    29  //   type CFTypeRef uintptr
    30  // and similar for other CF*Ref types.
    31  // This fix finds nils initializing these types and replaces the nils with 0s.
    32  func cftypefix(f *ast.File) bool {
    33  	return typefix(f, func(s string) bool {
    34  		return strings.HasPrefix(s, "C.CF") && strings.HasSuffix(s, "Ref")
    35  	})
    36  }
    37  
    38  // typefix replaces nil with 0 for all nils whose type, when passed to badType, returns true.
    39  func typefix(f *ast.File, badType func(string) bool) bool {
    40  	if !imports(f, "C") {
    41  		return false
    42  	}
    43  	typeof, _ := typecheck(&TypeConfig{}, f)
    44  
    45  	// step 1: Find all the nils with the offending types.
    46  	// Compute their replacement.
    47  	badNils := map[interface{}]ast.Expr{}
    48  	walk(f, func(n interface{}) {
    49  		if i, ok := n.(*ast.Ident); ok && i.Name == "nil" && badType(typeof[n]) {
    50  			badNils[n] = &ast.BasicLit{ValuePos: i.NamePos, Kind: token.INT, Value: "0"}
    51  		}
    52  	})
    53  	if len(badNils) == 0 {
    54  		return false
    55  	}
    56  
    57  	// step 2: find all uses of the bad nils, replace them with 0.
    58  	// There's no easy way to map from an ast.Expr to all the places that use them, so
    59  	// we use reflect to find all such references.
    60  	exprType := reflect.TypeOf((*ast.Expr)(nil)).Elem()
    61  	exprSliceType := reflect.TypeOf(([]ast.Expr)(nil))
    62  	walk(f, func(n interface{}) {
    63  		if n == nil {
    64  			return
    65  		}
    66  		v := reflect.ValueOf(n)
    67  		if v.Type().Kind() != reflect.Ptr {
    68  			return
    69  		}
    70  		if v.IsNil() {
    71  			return
    72  		}
    73  		v = v.Elem()
    74  		if v.Type().Kind() != reflect.Struct {
    75  			return
    76  		}
    77  		for i := 0; i < v.NumField(); i++ {
    78  			f := v.Field(i)
    79  			if f.Type() == exprType {
    80  				if r := badNils[f.Interface()]; r != nil {
    81  					f.Set(reflect.ValueOf(r))
    82  				}
    83  			}
    84  			if f.Type() == exprSliceType {
    85  				for j := 0; j < f.Len(); j++ {
    86  					e := f.Index(j)
    87  					if r := badNils[e.Interface()]; r != nil {
    88  						e.Set(reflect.ValueOf(r))
    89  					}
    90  				}
    91  			}
    92  		}
    93  	})
    94  
    95  	return true
    96  }