github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/cmd/signature-fuzzer/internal/fuzz-generator/structparm.go (about) 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 5 package generator 6 7 import ( 8 "bytes" 9 "fmt" 10 "strings" 11 ) 12 13 // structparm describes a parameter of struct type; it implements the 14 // "parm" interface. 15 type structparm struct { 16 sname string 17 qname string 18 fields []parm 19 isBlank 20 addrTakenHow 21 isGenValFunc 22 skipCompare 23 } 24 25 func (p structparm) TypeName() string { 26 return p.sname 27 } 28 29 func (p structparm) QualName() string { 30 return p.qname 31 } 32 33 func (p structparm) Declare(b *bytes.Buffer, prefix string, suffix string, caller bool) { 34 n := p.sname 35 if caller { 36 n = p.qname 37 } 38 b.WriteString(fmt.Sprintf("%s %s%s", prefix, n, suffix)) 39 } 40 41 func (p structparm) FieldName(i int) string { 42 if p.fields[i].IsBlank() { 43 return "_" 44 } 45 return fmt.Sprintf("F%d", i) 46 } 47 48 func (p structparm) String() string { 49 var buf bytes.Buffer 50 51 buf.WriteString(fmt.Sprintf("struct %s {\n", p.sname)) 52 for fi, f := range p.fields { 53 buf.WriteString(fmt.Sprintf("%s %s\n", p.FieldName(fi), f.String())) 54 } 55 buf.WriteString("}") 56 return buf.String() 57 } 58 59 func (p structparm) GenValue(s *genstate, f *funcdef, value int, caller bool) (string, int) { 60 var buf bytes.Buffer 61 62 verb(5, "structparm.GenValue(%d)", value) 63 64 n := p.sname 65 if caller { 66 n = p.qname 67 } 68 buf.WriteString(fmt.Sprintf("%s{", n)) 69 nbfi := 0 70 for fi, fld := range p.fields { 71 var valstr string 72 valstr, value = s.GenValue(f, fld, value, caller) 73 if p.fields[fi].IsBlank() { 74 buf.WriteString("/* ") 75 valstr = strings.ReplaceAll(valstr, "/*", "[[") 76 valstr = strings.ReplaceAll(valstr, "*/", "]]") 77 } else { 78 writeCom(&buf, nbfi) 79 } 80 buf.WriteString(p.FieldName(fi) + ": ") 81 buf.WriteString(valstr) 82 if p.fields[fi].IsBlank() { 83 buf.WriteString(" */") 84 } else { 85 nbfi++ 86 } 87 } 88 buf.WriteString("}") 89 return buf.String(), value 90 } 91 92 func (p structparm) IsControl() bool { 93 return false 94 } 95 96 func (p structparm) NumElements() int { 97 ne := 0 98 for _, f := range p.fields { 99 ne += f.NumElements() 100 } 101 return ne 102 } 103 104 func (p structparm) GenElemRef(elidx int, path string) (string, parm) { 105 ct := 0 106 verb(4, "begin GenElemRef(%d,%s) on %s", elidx, path, p.String()) 107 108 for fi, f := range p.fields { 109 fne := f.NumElements() 110 111 //verb(4, "+ examining field %d fne %d ct %d", fi, fne, ct) 112 113 // Empty field. Continue on. 114 if elidx == ct && fne == 0 { 115 continue 116 } 117 118 // Is this field the element we're interested in? 119 if fne == 1 && elidx == ct { 120 121 // The field in question may be a composite that has only 122 // multiple elements but a single non-zero-sized element. 123 // If this is the case, keep going. 124 if sp, ok := f.(*structparm); ok { 125 if len(sp.fields) > 1 { 126 ppath := fmt.Sprintf("%s.F%d", path, fi) 127 if p.fields[fi].IsBlank() || path == "_" { 128 ppath = "_" 129 } 130 return f.GenElemRef(elidx-ct, ppath) 131 } 132 } 133 134 verb(4, "found field %d type %s in GenElemRef(%d,%s)", fi, f.TypeName(), elidx, path) 135 ppath := fmt.Sprintf("%s.F%d", path, fi) 136 if p.fields[fi].IsBlank() || path == "_" { 137 ppath = "_" 138 } 139 return ppath, f 140 } 141 142 // Is the element we want somewhere inside this field? 143 if fne > 1 && elidx >= ct && elidx < ct+fne { 144 ppath := fmt.Sprintf("%s.F%d", path, fi) 145 if p.fields[fi].IsBlank() || path == "_" { 146 ppath = "_" 147 } 148 return f.GenElemRef(elidx-ct, ppath) 149 } 150 151 ct += fne 152 } 153 panic(fmt.Sprintf("GenElemRef failed for struct %s elidx %d", p.TypeName(), elidx)) 154 } 155 156 func (p structparm) HasPointer() bool { 157 for _, f := range p.fields { 158 if f.HasPointer() { 159 return true 160 } 161 } 162 return false 163 }