File: parm.go

package info (click to toggle)
golang-golang-x-tools 1%3A0.5.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bookworm-backports
  • size: 16,592 kB
  • sloc: javascript: 2,011; asm: 1,635; sh: 192; yacc: 155; makefile: 52; ansic: 8
file content (216 lines) | stat: -rw-r--r-- 6,430 bytes parent folder | download | duplicates (3)
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Copyright 2021 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 generator

import (
	"bytes"
	"fmt"
	"os"
	"sort"
)

// parm is an interface describing an abstract parameter var or return
// var; there will be concrete types of various sorts that implement
// this interface.
type parm interface {

	// Declare emits text containing a declaration of this param
	// or return var into the specified buffer. Prefix is a tag to
	// prepend before the declaration (for example a variable
	// name) followed by a space; suffix is an arbitrary string to
	// tack onto the end of the param's type text. Here 'caller'
	// is set to true if we're emitting the caller part of a test
	// pair as opposed to the checker.
	Declare(b *bytes.Buffer, prefix string, suffix string, caller bool)

	// GenElemRef returns a pair [X,Y] corresponding to a
	// component piece of some composite parm, where X is a string
	// forming the reference (ex: ".field" if we're picking out a
	// struct field) and Y is a parm object corresponding to the
	// type of the element.
	GenElemRef(elidx int, path string) (string, parm)

	// GenValue constructs a new concrete random value appropriate
	// for the type in question and returns it, along with a
	// sequence number indicating how many random decisions we had
	// to make. Here "s" is the current generator state, "f" is
	// the current function we're emitting, value is a sequence
	// number indicating how many random decisions have been made
	// up until this point, and 'caller' is set to true if we're
	// emitting the caller part of a test pair as opposed to the
	// checker.  Return value is a pair [V,I] where V is the text
	// if the value, and I is a new sequence number reflecting any
	// additional random choices we had to make.  For example, if
	// the parm is something like "type Foo struct { f1 int32; f2
	// float64 }" then we might expect GenValue to emit something
	// like "Foo{int32(-9), float64(123.123)}".
	GenValue(s *genstate, f *funcdef, value int, caller bool) (string, int)

	// IsControl returns true if this specific param has been marked
	// as the single param that controls recursion for a recursive
	// checker function. The test code doesn't check this param for a specific
	// value, but instead returns early if it has value 0 or decrements it
	// on a recursive call.
	IsControl() bool

	// NumElements returns the total number of discrete elements contained
	// in this parm. For non-composite types, this will always be 1.
	NumElements() int

	// String returns a descriptive string for this parm.
	String() string

	// TypeName returns the non-qualified type name for this parm.
	TypeName() string

	// QualName returns a package-qualified type name for this parm.
	QualName() string

	// HasPointer returns true if this parm is of pointer type, or
	// if it is a composite that has a pointer element somewhere inside.
	// Strings and slices return true for this hook.
	HasPointer() bool

	// IsBlank() returns true if the name of this parm is "_" (that is,
	// if we randomly chose to make it a blank). SetBlank() is used
	// to set the 'blank' property for this parm.
	IsBlank() bool
	SetBlank(v bool)

	// AddrTaken() return a token indicating whether this parm should
	// be address taken or not, the nature of the address-taken-ness (see
	// below at the def of addrTakenHow). SetAddrTaken is used to set
	// the address taken property of the parm.
	AddrTaken() addrTakenHow
	SetAddrTaken(val addrTakenHow)

	// IsGenVal() returns true if the values of this type should
	// be obtained by calling a helper func, as opposed to
	// emitting code inline (as one would for things like numeric
	// types). SetIsGenVal is used to set the gen-val property of
	// the parm.
	IsGenVal() bool
	SetIsGenVal(val bool)

	// SkipCompare() returns true if we've randomly decided that
	// we don't want to compare the value for this param or
	// return.  SetSkipCompare is used to set the skip-compare
	// property of the parm.
	SkipCompare() skipCompare
	SetSkipCompare(val skipCompare)
}

type addrTakenHow uint8

const (
	// Param not address taken.
	notAddrTaken addrTakenHow = 0

	// Param address is taken and used for simple reads/writes.
	addrTakenSimple addrTakenHow = 1

	// Param address is taken and passed to a well-behaved function.
	addrTakenPassed addrTakenHow = 2

	// Param address is taken and stored to a global var.
	addrTakenHeap addrTakenHow = 3
)

func (a *addrTakenHow) AddrTaken() addrTakenHow {
	return *a
}

func (a *addrTakenHow) SetAddrTaken(val addrTakenHow) {
	*a = val
}

type isBlank bool

func (b *isBlank) IsBlank() bool {
	return bool(*b)
}

func (b *isBlank) SetBlank(val bool) {
	*b = isBlank(val)
}

type isGenValFunc bool

func (g *isGenValFunc) IsGenVal() bool {
	return bool(*g)
}

func (g *isGenValFunc) SetIsGenVal(val bool) {
	*g = isGenValFunc(val)
}

type skipCompare int

const (
	// Param not address taken.
	SkipAll     = -1
	SkipNone    = 0
	SkipPayload = 1
)

func (s *skipCompare) SkipCompare() skipCompare {
	return skipCompare(*s)
}

func (s *skipCompare) SetSkipCompare(val skipCompare) {
	*s = skipCompare(val)
}

// containedParms takes an arbitrary param 'p' and returns a slice
// with 'p' itself plus any component parms contained within 'p'.
func containedParms(p parm) []parm {
	visited := make(map[string]parm)
	worklist := []parm{p}

	addToWork := func(p parm) {
		if p == nil {
			panic("not expected")
		}
		if _, ok := visited[p.TypeName()]; !ok {
			worklist = append(worklist, p)
		}
	}

	for len(worklist) != 0 {
		cp := worklist[0]
		worklist = worklist[1:]
		if _, ok := visited[cp.TypeName()]; ok {
			continue
		}
		visited[cp.TypeName()] = cp
		switch x := cp.(type) {
		case *mapparm:
			addToWork(x.keytype)
			addToWork(x.valtype)
		case *structparm:
			for _, fld := range x.fields {
				addToWork(fld)
			}
		case *arrayparm:
			addToWork(x.eltype)
		case *pointerparm:
			addToWork(x.totype)
		case *typedefparm:
			addToWork(x.target)
		}
	}
	rv := []parm{}
	for _, v := range visited {
		rv = append(rv, v)
	}
	sort.Slice(rv, func(i, j int) bool {
		if rv[i].TypeName() == rv[j].TypeName() {
			fmt.Fprintf(os.Stderr, "%d %d %+v %+v %s %s\n", i, j, rv[i], rv[i].String(), rv[j], rv[j].String())
			panic("unexpected")
		}
		return rv[i].TypeName() < rv[j].TypeName()
	})
	return rv
}