github.com/taylorchu/generic@v0.0.0-20171113184323-cd81575befa2/rewrite/remove_placeholder.go (about)

     1  package rewrite
     2  
     3  import (
     4  	"go/ast"
     5  )
     6  
     7  // removePlaceholder removes type declarations defined in typeMap.
     8  func (s *Spec) removePlaceholder(pkg *Package) error {
     9  	declMap := make(map[interface{}]struct{})
    10  	for _, node := range pkg.Files {
    11  		for i := len(node.Decls) - 1; i >= 0; i-- {
    12  			var remove bool
    13  			switch decl := node.Decls[i].(type) {
    14  			case *ast.GenDecl:
    15  				for _, spec := range decl.Specs {
    16  					switch spec := spec.(type) {
    17  					case *ast.TypeSpec:
    18  						_, ok := s.TypeMap[spec.Name.Name]
    19  						if !ok {
    20  							continue
    21  						}
    22  						_, ok = spec.Type.(*ast.Ident)
    23  						if !ok {
    24  							continue
    25  						}
    26  						remove = true
    27  						declMap[spec] = struct{}{}
    28  					}
    29  				}
    30  			}
    31  			if remove {
    32  				node.Decls = append(node.Decls[:i], node.Decls[i+1:]...)
    33  			}
    34  		}
    35  	}
    36  	// If a type placeholder is removed, its linked methods should be removed too.
    37  	// This works like go interface because now the replaced types need to implement these methods.
    38  	for _, node := range pkg.Files {
    39  		for i := len(node.Decls) - 1; i >= 0; i-- {
    40  			var remove bool
    41  			switch decl := node.Decls[i].(type) {
    42  			case *ast.FuncDecl:
    43  				if decl.Recv == nil {
    44  					continue
    45  				}
    46  				var obj *ast.Object
    47  				switch expr := decl.Recv.List[0].Type.(type) {
    48  				case *ast.StarExpr:
    49  					obj = expr.X.(*ast.Ident).Obj
    50  				case *ast.Ident:
    51  					obj = expr.Obj
    52  				}
    53  				if obj == nil || obj.Decl == nil {
    54  					continue
    55  				}
    56  				_, ok := declMap[obj.Decl]
    57  				if !ok {
    58  					continue
    59  				}
    60  				remove = true
    61  			}
    62  			if remove {
    63  				node.Decls = append(node.Decls[:i], node.Decls[i+1:]...)
    64  			}
    65  		}
    66  	}
    67  	return nil
    68  }