github.com/goplus/igop@v0.25.0/types_go118.go (about)

     1  //go:build go1.18
     2  // +build go1.18
     3  
     4  /*
     5   * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved.
     6   *
     7   * Licensed under the Apache License, Version 2.0 (the "License");
     8   * you may not use this file except in compliance with the License.
     9   * You may obtain a copy of the License at
    10   *
    11   *     http://www.apache.org/licenses/LICENSE-2.0
    12   *
    13   * Unless required by applicable law or agreed to in writing, software
    14   * distributed under the License is distributed on an "AS IS" BASIS,
    15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16   * See the License for the specific language governing permissions and
    17   * limitations under the License.
    18   */
    19  
    20  package igop
    21  
    22  import (
    23  	"go/ast"
    24  	"go/types"
    25  	"reflect"
    26  	"strconv"
    27  	"strings"
    28  
    29  	"golang.org/x/tools/go/ssa"
    30  	"golang.org/x/tools/go/types/typeutil"
    31  )
    32  
    33  const (
    34  	enabledTypeParam = true
    35  )
    36  
    37  func hasTypeParam(t types.Type) bool {
    38  	switch t := t.(type) {
    39  	case *types.TypeParam:
    40  		return true
    41  	case *types.Named:
    42  		return t.TypeParams() != nil
    43  	case *types.Signature:
    44  		return t.TypeParams() != nil
    45  	}
    46  	return false
    47  }
    48  
    49  type nestedStack struct {
    50  	targs []string
    51  	cache []*typeutil.Map
    52  }
    53  
    54  func (s *nestedStack) Push(targs string, cache *typeutil.Map) {
    55  	s.targs = append(s.targs, targs)
    56  	s.cache = append(s.cache, cache)
    57  }
    58  
    59  func (s *nestedStack) Pop() (targs string, cache *typeutil.Map) {
    60  	n := len(s.targs)
    61  	if n >= 1 {
    62  		targs = s.targs[n-1]
    63  		cache = s.cache[n-1]
    64  	}
    65  	s.targs = s.targs[:n-1]
    66  	s.cache = s.cache[:n-1]
    67  	return
    68  }
    69  
    70  func (r *TypesRecord) typeId(typ types.Type, t reflect.Type) string {
    71  	path := t.PkgPath()
    72  	if path == "" {
    73  		return t.String()
    74  	}
    75  	name := path + "." + t.Name()
    76  	if named, ok := typ.(*types.Named); ok {
    77  		if n := r.nested[named.Origin()]; n != 0 {
    78  			name += "ยท" + strconv.Itoa(n)
    79  		}
    80  	}
    81  	return name
    82  }
    83  
    84  func (r *TypesRecord) EnterInstance(fn *ssa.Function) {
    85  	r.ncache = &typeutil.Map{}
    86  	tp := fn.TypeParams()
    87  	for i := 0; i < tp.Len(); i++ {
    88  		rt, _ := r.ToType(fn.TypeArgs()[i])
    89  		r.ncache.Set(tp.At(i), rt)
    90  	}
    91  	r.nstack.Push(r.fntargs, r.ncache)
    92  	r.fntargs = r.parseFuncTypeArgs(fn)
    93  }
    94  
    95  func (r *TypesRecord) LeaveInstance(fn *ssa.Function) {
    96  	r.fntargs, r.ncache = r.nstack.Pop()
    97  }
    98  
    99  func (r *TypesRecord) parseFuncTypeArgs(fn *ssa.Function) (targs string) {
   100  	typeargs := fn.TypeArgs()
   101  	if len(typeargs) == 0 {
   102  		return
   103  	}
   104  	var args []string
   105  	for _, typ := range typeargs {
   106  		rt, _ := r.ToType(typ)
   107  		args = append(args, r.typeId(typ, rt))
   108  	}
   109  	return strings.Join(args, ",")
   110  }
   111  
   112  func (r *TypesRecord) extractNamed(named *types.Named, totype bool) (pkgpath string, name string, typeargs bool, nested bool) {
   113  	obj := named.Obj()
   114  	if pkg := obj.Pkg(); pkg != nil {
   115  		if pkg.Name() == "main" {
   116  			pkgpath = "main"
   117  		} else {
   118  			pkgpath = pkg.Path()
   119  		}
   120  	}
   121  	if r.fntargs != "" && r.nested[named.Origin()] != 0 {
   122  		nested = true
   123  	}
   124  	name = obj.Name()
   125  	var ids string = r.fntargs
   126  	if args := named.TypeArgs(); args != nil {
   127  		typeargs = true
   128  		var targs []string
   129  		for i := 0; i < args.Len(); i++ {
   130  			if totype {
   131  				typ := args.At(i)
   132  				rt, _ := r.ToType(typ)
   133  				targs = append(targs, r.typeId(typ, rt))
   134  			} else {
   135  				targs = append(targs, args.At(i).String())
   136  			}
   137  		}
   138  		if ids != "" {
   139  			ids += ";"
   140  		}
   141  		ids += strings.Join(targs, ",")
   142  	}
   143  	if ids != "" {
   144  		name += "[" + ids + "]"
   145  	}
   146  	return
   147  }
   148  
   149  func (r *TypesRecord) LookupReflect(typ types.Type) (rt reflect.Type, ok bool, nested bool) {
   150  	rt, ok = r.loader.LookupReflect(typ)
   151  	if !ok {
   152  		if r.ncache != nil {
   153  			if rt := r.ncache.At(typ); rt != nil {
   154  				return rt.(reflect.Type), true, true
   155  			}
   156  		}
   157  		n := len(r.nstack.cache)
   158  		for i := n; i > 0; i-- {
   159  			if rt := r.nstack.cache[i-1].At(typ); rt != nil {
   160  				return rt.(reflect.Type), true, true
   161  			}
   162  		}
   163  		if rt := r.tcache.At(typ); rt != nil {
   164  			return rt.(reflect.Type), true, false
   165  		}
   166  	}
   167  	return
   168  }
   169  
   170  func (r *TypesLoader) hasTypeArgs(rt reflect.Type) bool {
   171  	switch rt.Kind() {
   172  	case reflect.Pointer:
   173  		return r.hasTypeArgs(rt.Elem())
   174  	case reflect.Slice:
   175  		return r.hasTypeArgs(rt.Elem())
   176  	case reflect.Array:
   177  		return r.hasTypeArgs(rt.Elem())
   178  	case reflect.Chan:
   179  		return r.hasTypeArgs(rt.Elem())
   180  	case reflect.Map:
   181  		return r.hasTypeArgs(rt.Key()) || r.hasTypeArgs(rt.Elem())
   182  	case reflect.Struct:
   183  		if pkgPath := rt.PkgPath(); pkgPath != "" {
   184  			if pkg, ok := r.packages[pkgPath]; ok && pkg.Complete() {
   185  				name := rt.Name()
   186  				var typeArgs string
   187  				if n := strings.Index(name, "["); n != -1 {
   188  					if end := strings.LastIndex(name, "]"); end != -1 {
   189  						typeArgs = name[n+1 : end]
   190  						name = name[:n]
   191  					}
   192  				}
   193  				if obj := pkg.Scope().Lookup(name); obj != nil && len(typeArgs) > 0 {
   194  					return true
   195  				}
   196  			}
   197  		}
   198  	}
   199  	return false
   200  }
   201  
   202  func newTypesInfo() *types.Info {
   203  	return &types.Info{
   204  		Types:      make(map[ast.Expr]types.TypeAndValue),
   205  		Defs:       make(map[*ast.Ident]types.Object),
   206  		Uses:       make(map[*ast.Ident]types.Object),
   207  		Implicits:  make(map[ast.Node]types.Object),
   208  		Scopes:     make(map[ast.Node]*types.Scope),
   209  		Selections: make(map[*ast.SelectorExpr]*types.Selection),
   210  		Instances:  make(map[*ast.Ident]types.Instance),
   211  	}
   212  }