GoPLS Viewer

Home|gopls/cmd/signature-fuzzer/internal/fuzz-generator/parm.go
1// Copyright 2021 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package generator
6
7import (
8    "bytes"
9    "fmt"
10    "os"
11    "sort"
12)
13
14// parm is an interface describing an abstract parameter var or return
15// var; there will be concrete types of various sorts that implement
16// this interface.
17type parm interface {
18
19    // Declare emits text containing a declaration of this param
20    // or return var into the specified buffer. Prefix is a tag to
21    // prepend before the declaration (for example a variable
22    // name) followed by a space; suffix is an arbitrary string to
23    // tack onto the end of the param's type text. Here 'caller'
24    // is set to true if we're emitting the caller part of a test
25    // pair as opposed to the checker.
26    Declare(b *bytes.Bufferprefix stringsuffix stringcaller bool)
27
28    // GenElemRef returns a pair [X,Y] corresponding to a
29    // component piece of some composite parm, where X is a string
30    // forming the reference (ex: ".field" if we're picking out a
31    // struct field) and Y is a parm object corresponding to the
32    // type of the element.
33    GenElemRef(elidx intpath string) (stringparm)
34
35    // GenValue constructs a new concrete random value appropriate
36    // for the type in question and returns it, along with a
37    // sequence number indicating how many random decisions we had
38    // to make. Here "s" is the current generator state, "f" is
39    // the current function we're emitting, value is a sequence
40    // number indicating how many random decisions have been made
41    // up until this point, and 'caller' is set to true if we're
42    // emitting the caller part of a test pair as opposed to the
43    // checker.  Return value is a pair [V,I] where V is the text
44    // if the value, and I is a new sequence number reflecting any
45    // additional random choices we had to make.  For example, if
46    // the parm is something like "type Foo struct { f1 int32; f2
47    // float64 }" then we might expect GenValue to emit something
48    // like "Foo{int32(-9), float64(123.123)}".
49    GenValue(s *genstatef *funcdefvalue intcaller bool) (stringint)
50
51    // IsControl returns true if this specific param has been marked
52    // as the single param that controls recursion for a recursive
53    // checker function. The test code doesn't check this param for a specific
54    // value, but instead returns early if it has value 0 or decrements it
55    // on a recursive call.
56    IsControl() bool
57
58    // NumElements returns the total number of discrete elements contained
59    // in this parm. For non-composite types, this will always be 1.
60    NumElements() int
61
62    // String returns a descriptive string for this parm.
63    String() string
64
65    // TypeName returns the non-qualified type name for this parm.
66    TypeName() string
67
68    // QualName returns a package-qualified type name for this parm.
69    QualName() string
70
71    // HasPointer returns true if this parm is of pointer type, or
72    // if it is a composite that has a pointer element somewhere inside.
73    // Strings and slices return true for this hook.
74    HasPointer() bool
75
76    // IsBlank() returns true if the name of this parm is "_" (that is,
77    // if we randomly chose to make it a blank). SetBlank() is used
78    // to set the 'blank' property for this parm.
79    IsBlank() bool
80    SetBlank(v bool)
81
82    // AddrTaken() return a token indicating whether this parm should
83    // be address taken or not, the nature of the address-taken-ness (see
84    // below at the def of addrTakenHow). SetAddrTaken is used to set
85    // the address taken property of the parm.
86    AddrTaken() addrTakenHow
87    SetAddrTaken(val addrTakenHow)
88
89    // IsGenVal() returns true if the values of this type should
90    // be obtained by calling a helper func, as opposed to
91    // emitting code inline (as one would for things like numeric
92    // types). SetIsGenVal is used to set the gen-val property of
93    // the parm.
94    IsGenVal() bool
95    SetIsGenVal(val bool)
96
97    // SkipCompare() returns true if we've randomly decided that
98    // we don't want to compare the value for this param or
99    // return.  SetSkipCompare is used to set the skip-compare
100    // property of the parm.
101    SkipCompare() skipCompare
102    SetSkipCompare(val skipCompare)
103}
104
105type addrTakenHow uint8
106
107const (
108    // Param not address taken.
109    notAddrTaken addrTakenHow = 0
110
111    // Param address is taken and used for simple reads/writes.
112    addrTakenSimple addrTakenHow = 1
113
114    // Param address is taken and passed to a well-behaved function.
115    addrTakenPassed addrTakenHow = 2
116
117    // Param address is taken and stored to a global var.
118    addrTakenHeap addrTakenHow = 3
119)
120
121func (a *addrTakenHowAddrTaken() addrTakenHow {
122    return *a
123}
124
125func (a *addrTakenHowSetAddrTaken(val addrTakenHow) {
126    *a = val
127}
128
129type isBlank bool
130
131func (b *isBlankIsBlank() bool {
132    return bool(*b)
133}
134
135func (b *isBlankSetBlank(val bool) {
136    *b = isBlank(val)
137}
138
139type isGenValFunc bool
140
141func (g *isGenValFuncIsGenVal() bool {
142    return bool(*g)
143}
144
145func (g *isGenValFuncSetIsGenVal(val bool) {
146    *g = isGenValFunc(val)
147}
148
149type skipCompare int
150
151const (
152    // Param not address taken.
153    SkipAll     = -1
154    SkipNone    = 0
155    SkipPayload = 1
156)
157
158func (s *skipCompareSkipCompare() skipCompare {
159    return skipCompare(*s)
160}
161
162func (s *skipCompareSetSkipCompare(val skipCompare) {
163    *s = skipCompare(val)
164}
165
166// containedParms takes an arbitrary param 'p' and returns a slice
167// with 'p' itself plus any component parms contained within 'p'.
168func containedParms(p parm) []parm {
169    visited := make(map[string]parm)
170    worklist := []parm{p}
171
172    addToWork := func(p parm) {
173        if p == nil {
174            panic("not expected")
175        }
176        if _ok := visited[p.TypeName()]; !ok {
177            worklist = append(worklistp)
178        }
179    }
180
181    for len(worklist) != 0 {
182        cp := worklist[0]
183        worklist = worklist[1:]
184        if _ok := visited[cp.TypeName()]; ok {
185            continue
186        }
187        visited[cp.TypeName()] = cp
188        switch x := cp.(type) {
189        case *mapparm:
190            addToWork(x.keytype)
191            addToWork(x.valtype)
192        case *structparm:
193            for _fld := range x.fields {
194                addToWork(fld)
195            }
196        case *arrayparm:
197            addToWork(x.eltype)
198        case *pointerparm:
199            addToWork(x.totype)
200        case *typedefparm:
201            addToWork(x.target)
202        }
203    }
204    rv := []parm{}
205    for _v := range visited {
206        rv = append(rvv)
207    }
208    sort.Slice(rv, func(ij intbool {
209        if rv[i].TypeName() == rv[j].TypeName() {
210            fmt.Fprintf(os.Stderr"%d %d %+v %+v %s %s\n"ijrv[i], rv[i].String(), rv[j], rv[j].String())
211            panic("unexpected")
212        }
213        return rv[i].TypeName() < rv[j].TypeName()
214    })
215    return rv
216}
217
MembersX
sort
addrTakenHeap
isGenValFunc.IsGenVal
containedParms.BlockStmt.BlockStmt.RangeStmt_5896.fld
containedParms.rv
addrTakenHow.AddrTaken.a
addrTakenHow.SetAddrTaken
isBlank
isBlank.IsBlank
skipCompare.SetSkipCompare.val
containedParms.p
containedParms.RangeStmt_6105.v
addrTakenPassed
addrTakenHow.SetAddrTaken.a
SkipPayload
skipCompare.SetSkipCompare
containedParms
addrTakenHow.AddrTaken
isGenValFunc.SetIsGenVal.val
SkipNone
skipCompare.SkipCompare
containedParms.visited
skipCompare.SkipCompare.s
addrTakenHow.SetAddrTaken.val
isBlank.SetBlank.b
isBlank.SetBlank
isBlank.SetBlank.val
skipCompare
skipCompare.SetSkipCompare.s
addrTakenHow
notAddrTaken
addrTakenSimple
isBlank.IsBlank.b
isGenValFunc.SetIsGenVal
isGenValFunc
containedParms.worklist
parm
isGenValFunc.IsGenVal.g
isGenValFunc.SetIsGenVal.g
Members
X