blob: a5cd7e8dbfcb9d9f7f46475dc04067ccec634fa9 [file] [log] [blame]
// 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{},
}
}