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  }