| // Copyright 2020 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package typesinternal provides access to internal go/types APIs that are not |
| // yet exported. |
| package typesinternal |
| |
| import ( |
| "go/ast" |
| "go/token" |
| "go/types" |
| "reflect" |
| "unsafe" |
| |
| "golang.org/x/tools/internal/aliases" |
| ) |
| |
| func SetUsesCgo(conf *types.Config) bool { |
| v := reflect.ValueOf(conf).Elem() |
| |
| f := v.FieldByName("go115UsesCgo") |
| if !f.IsValid() { |
| f = v.FieldByName("UsesCgo") |
| if !f.IsValid() { |
| return false |
| } |
| } |
| |
| addr := unsafe.Pointer(f.UnsafeAddr()) |
| *(*bool)(addr) = true |
| |
| return true |
| } |
| |
| // ErrorCodeStartEnd extracts additional information from types.Error values |
| // generated by Go version 1.16 and later: the error code, start position, and |
| // end position. If all positions are valid, start <= err.Pos <= end. |
| // |
| // If the data could not be read, the final result parameter will be false. |
| // |
| // TODO(adonovan): eliminate start/end when proposal #71803 is accepted. |
| func ErrorCodeStartEnd(err types.Error) (code ErrorCode, start, end token.Pos, ok bool) { |
| var data [3]int |
| // By coincidence all of these fields are ints, which simplifies things. |
| v := reflect.ValueOf(err) |
| for i, name := range []string{"go116code", "go116start", "go116end"} { |
| f := v.FieldByName(name) |
| if !f.IsValid() { |
| return 0, 0, 0, false |
| } |
| data[i] = int(f.Int()) |
| } |
| return ErrorCode(data[0]), token.Pos(data[1]), token.Pos(data[2]), true |
| } |
| |
| // NameRelativeTo returns a types.Qualifier that qualifies members of |
| // all packages other than pkg, using only the package name. |
| // (By contrast, [types.RelativeTo] uses the complete package path, |
| // which is often excessive.) |
| // |
| // If pkg is nil, it is equivalent to [*types.Package.Name]. |
| func NameRelativeTo(pkg *types.Package) types.Qualifier { |
| return func(other *types.Package) string { |
| if pkg != nil && pkg == other { |
| return "" // same package; unqualified |
| } |
| return other.Name() |
| } |
| } |
| |
| // TypeNameFor returns the type name symbol for the specified type, if |
| // it is a [*types.Alias], [*types.Named], [*types.TypeParam], or a |
| // [*types.Basic] representing a type. |
| // |
| // For all other types, and for Basic types representing a builtin, |
| // constant, or nil, it returns nil. Be careful not to convert the |
| // resulting nil pointer to a [types.Object]! |
| // |
| // If t is the type of a constant, it may be an "untyped" type, which |
| // has no TypeName. To access the name of such types (e.g. "untyped |
| // int"), use [types.Basic.Name]. |
| func TypeNameFor(t types.Type) *types.TypeName { |
| switch t := t.(type) { |
| case *types.Alias: |
| return t.Obj() |
| case *types.Named: |
| return t.Obj() |
| case *types.TypeParam: |
| return t.Obj() |
| case *types.Basic: |
| // See issues #71886 and #66890 for some history. |
| if tname, ok := types.Universe.Lookup(t.Name()).(*types.TypeName); ok { |
| return tname |
| } |
| } |
| return nil |
| } |
| |
| // A NamedOrAlias is a [types.Type] that is named (as |
| // defined by the spec) and capable of bearing type parameters: it |
| // abstracts aliases ([types.Alias]) and defined types |
| // ([types.Named]). |
| // |
| // Every type declared by an explicit "type" declaration is a |
| // NamedOrAlias. (Built-in type symbols may additionally |
| // have type [types.Basic], which is not a NamedOrAlias, |
| // though the spec regards them as "named"; see [TypeNameFor].) |
| // |
| // NamedOrAlias cannot expose the Origin method, because |
| // [types.Alias.Origin] and [types.Named.Origin] have different |
| // (covariant) result types; use [Origin] instead. |
| type NamedOrAlias interface { |
| types.Type |
| Obj() *types.TypeName |
| TypeArgs() *types.TypeList |
| TypeParams() *types.TypeParamList |
| SetTypeParams(tparams []*types.TypeParam) |
| } |
| |
| var ( |
| _ NamedOrAlias = (*types.Alias)(nil) |
| _ NamedOrAlias = (*types.Named)(nil) |
| ) |
| |
| // Origin returns the generic type of the Named or Alias type t if it |
| // is instantiated, otherwise it returns t. |
| func Origin(t NamedOrAlias) NamedOrAlias { |
| switch t := t.(type) { |
| case *types.Alias: |
| return aliases.Origin(t) |
| case *types.Named: |
| return t.Origin() |
| } |
| return t |
| } |
| |
| // IsPackageLevel reports whether obj is a package-level symbol. |
| func IsPackageLevel(obj types.Object) bool { |
| return obj.Pkg() != nil && obj.Parent() == obj.Pkg().Scope() |
| } |
| |
| // NewTypesInfo returns a *types.Info with all maps populated. |
| func NewTypesInfo() *types.Info { |
| return &types.Info{ |
| Types: map[ast.Expr]types.TypeAndValue{}, |
| Instances: map[*ast.Ident]types.Instance{}, |
| Defs: map[*ast.Ident]types.Object{}, |
| Uses: map[*ast.Ident]types.Object{}, |
| Implicits: map[ast.Node]types.Object{}, |
| Selections: map[*ast.SelectorExpr]*types.Selection{}, |
| Scopes: map[ast.Node]*types.Scope{}, |
| FileVersions: map[*ast.File]string{}, |
| } |
| } |