File: util.go

package info (click to toggle)
golang-honnef-go-tools 2023.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 4,784 kB
  • sloc: sh: 132; xml: 48; lisp: 30; makefile: 10; javascript: 1
file content (148 lines) | stat: -rw-r--r-- 3,481 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2013 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 ir

// This file defines a number of miscellaneous utility functions.

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"io"
	"os"

	"honnef.co/go/tools/go/ast/astutil"
	"honnef.co/go/tools/go/types/typeutil"
)

//// AST utilities

func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }

// isBlankIdent returns true iff e is an Ident with name "_".
// They have no associated types.Object, and thus no type.
func isBlankIdent(e ast.Expr) bool {
	id, ok := e.(*ast.Ident)
	return ok && id.Name == "_"
}

//// Type utilities.  Some of these belong in go/types.

// isPointer returns true for types whose underlying type is a pointer,
// and for type parameters whose core type is a pointer.
func isPointer(typ types.Type) bool {
	if ctyp := typeutil.CoreType(typ); ctyp != nil {
		_, ok := ctyp.(*types.Pointer)
		return ok
	}
	_, ok := typ.Underlying().(*types.Pointer)
	return ok
}

func isInterface(T types.Type) bool { return types.IsInterface(T) }

// deref returns a pointer's element type; otherwise it returns typ.
func deref(typ types.Type) types.Type {
	orig := typ

	if t, ok := typ.(*types.TypeParam); ok {
		if ctyp := typeutil.CoreType(t); ctyp != nil {
			typ = ctyp
		}
	}
	if p, ok := typ.Underlying().(*types.Pointer); ok {
		return p.Elem()
	}
	return orig
}

// recvType returns the receiver type of method obj.
func recvType(obj *types.Func) types.Type {
	return obj.Type().(*types.Signature).Recv().Type()
}

// logStack prints the formatted "start" message to stderr and
// returns a closure that prints the corresponding "end" message.
// Call using 'defer logStack(...)()' to show builder stack on panic.
// Don't forget trailing parens!
func logStack(format string, args ...interface{}) func() {
	msg := fmt.Sprintf(format, args...)
	io.WriteString(os.Stderr, msg)
	io.WriteString(os.Stderr, "\n")
	return func() {
		io.WriteString(os.Stderr, msg)
		io.WriteString(os.Stderr, " end\n")
	}
}

// newVar creates a 'var' for use in a types.Tuple.
func newVar(name string, typ types.Type) *types.Var {
	return types.NewParam(token.NoPos, nil, name, typ)
}

// anonVar creates an anonymous 'var' for use in a types.Tuple.
func anonVar(typ types.Type) *types.Var {
	return newVar("", typ)
}

var lenResults = types.NewTuple(anonVar(tInt))

// makeLen returns the len builtin specialized to type func(T)int.
func makeLen(T types.Type) *Builtin {
	lenParams := types.NewTuple(anonVar(T))
	return &Builtin{
		name: "len",
		sig:  types.NewSignatureType(nil, nil, nil, lenParams, lenResults, false),
	}
}

type StackMap struct {
	m []map[Value]Value
}

func (m *StackMap) Push() {
	m.m = append(m.m, map[Value]Value{})
}

func (m *StackMap) Pop() {
	m.m = m.m[:len(m.m)-1]
}

func (m *StackMap) Get(key Value) (Value, bool) {
	for i := len(m.m) - 1; i >= 0; i-- {
		if v, ok := m.m[i][key]; ok {
			return v, true
		}
	}
	return nil, false
}

func (m *StackMap) Set(k Value, v Value) {
	m.m[len(m.m)-1][k] = v
}

// Unwrap recursively unwraps Sigma and Copy nodes.
func Unwrap(v Value) Value {
	for {
		switch vv := v.(type) {
		case *Sigma:
			v = vv.X
		case *Copy:
			v = vv.X
		default:
			return v
		}
	}
}

func assert(x bool) {
	if !x {
		panic("failed assertion")
	}
}

// BlockMap is a mapping from basic blocks (identified by their indices) to values.
type BlockMap[T any] []T