github.com/gotranspile/cxgo@v0.3.7/parse_test.go (about)

     1  package cxgo
     2  
     3  import (
     4  	"bytes"
     5  	"runtime/debug"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  	"modernc.org/cc/v3"
    12  
    13  	"github.com/gotranspile/cxgo/libs"
    14  	"github.com/gotranspile/cxgo/types"
    15  )
    16  
    17  const testPkg = "lib"
    18  
    19  type configFunc func(c *Config)
    20  type envFunc func(c *types.Config)
    21  
    22  type parseCase struct {
    23  	name        string
    24  	inc         string
    25  	src         string
    26  	exp         string
    27  	skipExp     string
    28  	skip        bool
    29  	builtins    bool
    30  	configFuncs []configFunc
    31  	envFuncs    []envFunc
    32  }
    33  
    34  func (c parseCase) shouldSkip() bool {
    35  	return c.skip || c.skipExp != ""
    36  }
    37  
    38  func withIdent(ic IdentConfig) configFunc {
    39  	return func(c *Config) {
    40  		c.Idents = append(c.Idents, ic)
    41  	}
    42  }
    43  
    44  func withIdentField(name string, f IdentConfig) configFunc {
    45  	return withIdent(IdentConfig{Name: name, Fields: []IdentConfig{f}})
    46  }
    47  
    48  func withAlias(name string) configFunc {
    49  	return func(c *Config) {
    50  		c.Idents = append(c.Idents, IdentConfig{Name: name, Alias: true})
    51  	}
    52  }
    53  
    54  func withRename(from, to string) configFunc {
    55  	return func(c *Config) {
    56  		c.Idents = append(c.Idents, IdentConfig{Name: from, Rename: to})
    57  	}
    58  }
    59  
    60  var casesTranslate = []parseCase{
    61  	{
    62  		name: "empty",
    63  		src:  " ",
    64  	},
    65  	{
    66  		name: "push defines",
    67  		src: `
    68  #define BLAH 10
    69  
    70  int v1 = BLAH;
    71  
    72  #pragma push_macro("BLAH")
    73  #undef BLAH
    74  #define BLAH 5
    75  
    76  int v2 = BLAH;
    77  
    78  #pragma pop_macro("BLAH")
    79  
    80  int v3 = BLAH;
    81  
    82  #pragma push_macro("NON_EXISTENT")
    83  #pragma pop_macro("NON_EXISTENT")
    84  `,
    85  		exp: `
    86  const BLAH = 10
    87  const BLAH = 5
    88  
    89  var v1 int32 = BLAH
    90  var v2 int32 = BLAH
    91  var v3 int32 = BLAH
    92  `,
    93  		skipExp: `
    94  const BLAH = 10
    95  
    96  var v1 int32 = BLAH
    97  var v2 int32 = BLAH
    98  var v3 int32 = BLAH
    99  `,
   100  	},
   101  	{
   102  		name: "switch",
   103  		src: `
   104  void foo(int a) {
   105  	switch (a) {
   106  	case 1:
   107  		foo(1);
   108  		break;
   109  	case 2:
   110  		foo(2);
   111  	default:
   112  		foo(0);
   113  	case 3:
   114  		foo(3);
   115  		break;
   116  	case 4:
   117  	case 5:
   118  		foo(5);
   119  		return;
   120  	case 6:
   121  		foo(6);
   122  	}
   123  }
   124  `,
   125  		exp: `
   126  func foo(a int32) {
   127  	switch a {
   128  	case 1:
   129  		foo(1)
   130  	case 2:
   131  		foo(2)
   132  		fallthrough
   133  	default:
   134  		foo(0)
   135  		fallthrough
   136  	case 3:
   137  		foo(3)
   138  	case 4:
   139  		fallthrough
   140  	case 5:
   141  		foo(5)
   142  		return
   143  	case 6:
   144  		foo(6)
   145  	}
   146  }
   147  `,
   148  	},
   149  	{
   150  		skip: true,
   151  		name: "switch cases everywhere",
   152  		src: `
   153  void foo(int p, char s) {
   154      switch (p) {
   155      case 0:
   156          if (s == 'a') {
   157      case 1:
   158  			s = 'c';
   159          }
   160          break;
   161      }
   162  }
   163  `,
   164  		exp: `
   165  func foo(p int32, s int8) {
   166  	switch p {
   167  	case 1:
   168  		goto case_1
   169  	case 0:
   170  		if s == 'a' {
   171  		case_1:
   172  			s = 'c'
   173  		}
   174  	}
   175  }
   176  `,
   177  	},
   178  	{
   179  		skip: true,
   180  		name: "switch cases everywhere 2",
   181  		src: `
   182  void foo(int p, char s) {
   183      switch (p) {
   184  	if (s) {
   185      case 0:
   186          if (s == 'a') {
   187      case 1:
   188  			s = 'c';
   189          }
   190          break;
   191  	}
   192  	case 2:
   193  		s = 'd';
   194          break;
   195      }
   196  }
   197  `,
   198  		exp: `
   199  func foo(p int32, s int8) {
   200  	switch {
   201  	case s != 0 && p == 1:
   202  		goto case_1
   203  	case s != 0 && p == 0:
   204  		if s == 'a' {
   205  		case_1:
   206  			s = 'c'
   207  		}
   208  	case p == 2
   209  		s = 'd'
   210  	}
   211  }
   212  `,
   213  	},
   214  	{
   215  		name: "revert last if",
   216  		skip: !optimizeStatements,
   217  		src: `
   218  int foo(int* a, int* b) {
   219  	if (a) {
   220  		foo(a);
   221  		foo(a);
   222  		foo(a);
   223  	}
   224  	foo(b);
   225  	return 1;
   226  }
   227  `,
   228  		exp: `
   229  func foo(a *int32, b *int32) int32 {
   230  	if a == nil {
   231  		foo(b)
   232  		return 1
   233  	}
   234  	foo(a)
   235  	foo(a)
   236  	foo(a)
   237  	foo(b)
   238  	return 1
   239  }
   240  `,
   241  	},
   242  	{
   243  		name: "revert last if goto",
   244  		skip: !optimizeStatements,
   245  		src: `
   246  int foo(int* a, int* b) {
   247  	if (a) {
   248  		foo(a);
   249  		foo(a);
   250  		foo(a);
   251  	}
   252  LABEL_X:
   253  	foo(b);
   254  	return 1;
   255  }
   256  `,
   257  		exp: `
   258  func foo(a *int32, b *int32) int32 {
   259  	if a == nil {
   260  		foo(b)
   261  		return 1
   262  	}
   263  	foo(a)
   264  	foo(a)
   265  	foo(a)
   266  	foo(b)
   267  	return 1
   268  }
   269  `,
   270  	},
   271  	{
   272  		name: "revert last if void",
   273  		skip: !optimizeStatements,
   274  		src: `
   275  void foo(int* a) {
   276  	if (a) {
   277  		foo(a);
   278  		foo(a);
   279  		foo(a);
   280  	}
   281  }
   282  `,
   283  		exp: `
   284  func foo(a *int32) {
   285  	if a == nil {
   286  		return
   287  	}
   288  	foo(a)
   289  	foo(a)
   290  	foo(a)
   291  }
   292  `,
   293  	},
   294  	{
   295  		name: "move return to if",
   296  		skip: !optimizeStatements,
   297  		src: `
   298  int foo(int* a) {
   299  	if (a) {
   300  		foo(a);
   301  	} else {
   302  		foo(a);
   303  	}
   304  	return 1;
   305  }
   306  `,
   307  		exp: `
   308  func foo(a *int32) int32 {
   309  	if a != nil {
   310  		foo(a)
   311  		return 1
   312  	}
   313  	foo(a)
   314  	return 1
   315  }
   316  `,
   317  	},
   318  	{
   319  		name: "move return to if nested",
   320  		skip: !optimizeStatements,
   321  		src: `
   322  int foo(int a) {
   323  	if (a == 1) {
   324  		foo(2);
   325  		if (a == 3) {
   326  			foo(4);
   327  		} else if (a == 5) {
   328  			foo(6);
   329  		}
   330  	}
   331  	return 1;
   332  }
   333  `,
   334  		exp: `
   335  func foo(a int32) int32 {
   336  	if a != 1 {
   337  		return 1
   338  	}
   339  	foo(2)
   340  	if a == 3 {
   341  		foo(4)
   342  		return 1
   343  	} else if a == 5 {
   344  		foo(6)
   345  		return 1
   346  	}
   347  	return 1
   348  }
   349  `,
   350  	},
   351  	{
   352  		name: "revert last if cost",
   353  		skip: !optimizeStatements,
   354  		src: `
   355  int foo(int* a) {
   356  	if (a) {
   357  		foo(a);
   358  		foo(a);
   359  		if (a) {
   360  			foo(a);
   361  		}
   362  		foo(a);
   363  		return 1;
   364  	}
   365  	foo(a);
   366  	foo(a);
   367  	foo(a);
   368  	return 0;
   369  }
   370  `,
   371  		exp: `
   372  func foo(a *int32) int32 {
   373  	if a == nil {
   374  		foo(a)
   375  		foo(a)
   376  		foo(a)
   377  		return 0
   378  	}
   379  	foo(a)
   380  	foo(a)
   381  	if a != nil {
   382  		foo(a)
   383  	}
   384  	foo(a)
   385  	return 1
   386  }
   387  `,
   388  	},
   389  	{
   390  		name: "sub_40BC10",
   391  		inc:  `typedef unsigned int _DWORD;`,
   392  		src: `
   393  unsigned char blob[10];
   394  char* foo(int a) {
   395  	return (char*)(*(_DWORD*)& blob[3] + 160 * a);
   396  }
   397  `,
   398  		exp: `
   399  var blob [10]uint8
   400  
   401  func foo(a int32) *byte {
   402  	return (*byte)(unsafe.Pointer(uintptr(*(*_DWORD)(unsafe.Pointer(&blob[3])) + _DWORD(a*160))))
   403  }
   404  `,
   405  	},
   406  	{
   407  		name: "inline gotos",
   408  		skip: !optimizeStatements,
   409  		src: `
   410  int foo(int* a) {
   411  	if (a) {
   412  		foo(a);
   413  LABEL_2:
   414  		foo(a);
   415  		if (a) {
   416  			foo(a);
   417  			goto LABEL_1;
   418  		}
   419  LABEL_1:
   420  		foo(a);
   421  		return 1;
   422  	}
   423  	foo(a);
   424  	foo(a);
   425  	goto LABEL_2;
   426  }
   427  `,
   428  		exp: `
   429  func foo(a *int32) int32 {
   430  	if a == nil {
   431  		foo(a)
   432  		foo(a)
   433  		goto LABEL_2
   434  	}
   435  	foo(a)
   436  LABEL_2:
   437  	foo(a)
   438  	if a == nil {
   439  		foo(a)
   440  		return 1
   441  	}
   442  	foo(a)
   443  	foo(a)
   444  	return 1
   445  }
   446  `,
   447  	},
   448  	{
   449  		name: "inline gotos chain",
   450  		skip: !optimizeStatements,
   451  		src: `
   452  int foo(int* a) {
   453  	if (a) {
   454  		foo(a);
   455  		foo(a);
   456  		if (a) {
   457  LABEL_2:
   458  			foo(a);
   459  			goto LABEL_1;
   460  		}
   461  LABEL_1:
   462  		foo(a);
   463  		return 1;
   464  	}
   465  	foo(a);
   466  	foo(a);
   467  	goto LABEL_2;
   468  }
   469  `,
   470  		exp: `
   471  func foo(a *int32) int32 {
   472  	if a == nil {
   473  		foo(a)
   474  		foo(a)
   475  		foo(a)
   476  		foo(a)
   477  		return 1
   478  	}
   479  	foo(a)
   480  	foo(a)
   481  	if a == nil {
   482  		foo(a)
   483  		return 1
   484  	}
   485  	foo(a)
   486  	foo(a)
   487  	return 1
   488  }
   489  `,
   490  	},
   491  	{
   492  		name: "blocks with vars",
   493  		src: `
   494  #define set(s) \
   495  { int t = s;\
   496  }
   497  
   498  void main() {
   499    int s;
   500    if (0) {
   501      set(s)
   502      set(s)
   503      set(s)
   504    }
   505  }
   506  `,
   507  		exp: `
   508  func main() {
   509  	var s int32
   510  	if false {
   511  		{
   512  			var t int32 = s
   513  			_ = t
   514  		}
   515  		{
   516  			var t int32 = s
   517  			_ = t
   518  		}
   519  		{
   520  			var t int32 = s
   521  			_ = t
   522  		}
   523  	}
   524  }
   525  `,
   526  	},
   527  	{
   528  		name: "blocks no vars",
   529  		src: `
   530  #define set(s) \
   531  { t = s;\
   532  }
   533  
   534  void main() {
   535    int s, t;
   536    if (0) {
   537      set(s)
   538      set(s)
   539      set(s)
   540    }
   541  }
   542  `,
   543  		exp: `
   544  func main() {
   545  	var (
   546  		s int32
   547  		t int32
   548  	)
   549  	_ = t
   550  	if false {
   551  		t = s
   552  		t = s
   553  		t = s
   554  	}
   555  }
   556  `,
   557  	},
   558  	{
   559  		name:     "sizeof only",
   560  		builtins: true,
   561  		src: `
   562  int a = sizeof(int);
   563  `,
   564  		exp: `
   565  var a int32 = int32(unsafe.Sizeof(int32(0)))
   566  `,
   567  	},
   568  	{
   569  		name:     "sizeof",
   570  		builtins: true,
   571  		src: `
   572  void foo() {
   573  	size_t a;
   574  	int b[10];
   575  	unsigned char b2[10];
   576  	void* c;
   577  	int* d;
   578  	int (*e)(void);
   579  	a = sizeof(b);
   580  	a = sizeof(b2);
   581  	a = sizeof(c);
   582  	a = sizeof(d);
   583  	a = sizeof(e);
   584  }
   585  `,
   586  		exp: `
   587  func foo() {
   588  	var a size_t
   589  	_ = a
   590  	var b [10]int32
   591  	_ = b
   592  	var b2 [10]uint8
   593  	_ = b2
   594  	var c unsafe.Pointer
   595  	_ = c
   596  	var d *int32
   597  	_ = d
   598  	var e func() int32
   599  	_ = e
   600  	a = size_t(unsafe.Sizeof([10]int32{}))
   601  	a = size_t(10)
   602  	a = size_t(unsafe.Sizeof(unsafe.Pointer(nil)))
   603  	a = size_t(unsafe.Sizeof((*int32)(nil)))
   604  	a = size_t(unsafe.Sizeof(uintptr(0)))
   605  }
   606  `,
   607  	},
   608  	{
   609  		name: "assign expr",
   610  		src: `
   611  void foo() {
   612  	int a;
   613  	int b;
   614  	b = a = 1;
   615  }
   616  `,
   617  		exp: `
   618  func foo() {
   619  	var (
   620  		a int32
   621  		b int32
   622  	)
   623  	_ = b
   624  	b = func() int32 {
   625  		a = 1
   626  		return a
   627  	}()
   628  }
   629  `,
   630  	},
   631  	{
   632  		name: "stdint override",
   633  		src: `
   634  #include <stdint.h>
   635  
   636  void foo() {
   637  	int16_t a1;
   638  	uint32_t a2;
   639  }
   640  `,
   641  		exp: `
   642  func foo() {
   643  	var a1 int16
   644  	_ = a1
   645  	var a2 uint32
   646  	_ = a2
   647  }
   648  `,
   649  	},
   650  	{
   651  		name: "void cast",
   652  		src: `
   653  void foo(int a, int* b) {
   654  	int c;
   655  	(void)a;
   656  	(void)b;
   657  	(void)c;
   658  }
   659  `,
   660  		exp: `
   661  func foo(a int32, b *int32) {
   662  	var c int32
   663  	_ = a
   664  	_ = b
   665  	_ = c
   666  }
   667  `,
   668  	},
   669  	{
   670  		name: "assign ternary",
   671  		src: `
   672  void foo(int a) {
   673  	a = a ? 1 : 0;
   674  	a = -(a ? 1 : 0);
   675  	int b = a ? 1 : 0;
   676  }
   677  `,
   678  		exp: `
   679  func foo(a int32) {
   680  	if a != 0 {
   681  		a = 1
   682  	} else {
   683  		a = 0
   684  	}
   685  	if a != 0 {
   686  		a = -1
   687  	} else {
   688  		a = 0
   689  	}
   690  	var b int32
   691  	_ = b
   692  	if a != 0 {
   693  		b = 1
   694  	} else {
   695  		b = 0
   696  	}
   697  }
   698  `,
   699  	},
   700  	{
   701  		name: "return ternary",
   702  		src: `
   703  int foo(int a) {
   704  	return a ? 1 : 0;
   705  }
   706  `,
   707  		exp: `
   708  func foo(a int32) int32 {
   709  	if a != 0 {
   710  		return 1
   711  	}
   712  	return 0
   713  }
   714  `,
   715  	},
   716  	{
   717  		skip: true,
   718  		name: "multiple assignments",
   719  		src: `
   720  void foo(int a) {
   721  	int b, c;
   722  	c = b = a;
   723  	c = b = a++;
   724  	c = b = ++a;
   725  }
   726  `,
   727  		exp: `
   728  func foo(a int32) {
   729  	var b, c int32
   730  	b, c = a, a
   731  	b, c = a, a
   732  	a++
   733  	a++
   734  	b, c = a, a
   735  }
   736  `,
   737  	},
   738  	{
   739  		skip: true,
   740  		name: "if init 1",
   741  		src: `
   742  void foo(int a) {
   743  	if (a = 1, a) {
   744  		a = 0;
   745  	}
   746  }
   747  `,
   748  		exp: `
   749  func foo(a int32) {
   750  	if a = 1; a != 0 {
   751  		a = 0
   752  	}
   753  }
   754  `,
   755  	},
   756  	{
   757  		skip: true,
   758  		name: "if init 2",
   759  		src: `
   760  void foo(int a) {
   761  	if (a = 1) {
   762  		a = 0;
   763  	}
   764  }
   765  `,
   766  		exp: `
   767  func foo(a int32) {
   768  	if a = 1; a != 0 {
   769  		a = 0
   770  	}
   771  }
   772  `,
   773  	},
   774  	{
   775  		skip: true,
   776  		name: "if init 3",
   777  		src: `
   778  void foo(int a) {
   779  	if ((a = 1) != 0) {
   780  		a = 0;
   781  	}
   782  }
   783  `,
   784  		exp: `
   785  func foo(a int32) {
   786  	if a = 1; a != 0 {
   787  		a = 0
   788  	}
   789  }
   790  `,
   791  	},
   792  	{
   793  		name: "multiple stmt splits",
   794  		src: `
   795  typedef struct list_t list_t;
   796  typedef struct list_t {
   797  	list_t* next;
   798  } list_t;
   799  
   800  void foo() {
   801  	list_t *elt, *list;
   802  	for (elt=list; elt ? (list=elt->next, elt->next=0), 1 : 0; elt=list) {}
   803  }
   804  `,
   805  		exp: `
   806  type list_t struct {
   807  	Next *list_t
   808  }
   809  
   810  func foo() {
   811  	var (
   812  		elt  *list_t
   813  		list *list_t
   814  	)
   815  	for elt = list; func() int {
   816  		if elt != nil {
   817  			return func() int {
   818  				list = elt.Next
   819  				elt.Next = nil
   820  				return 1
   821  			}()
   822  		}
   823  		return 0
   824  	}() != 0; elt = list {
   825  	}
   826  }
   827  `,
   828  		envFuncs: []envFunc{func(c *types.Config) {
   829  			c.UseGoInt = true
   830  		}},
   831  	},
   832  }
   833  
   834  func TestTranslate(t *testing.T) {
   835  	runTestTranslate(t, casesTranslate)
   836  }
   837  
   838  func runTestTranslateCase(t *testing.T, c parseCase) {
   839  	if c.shouldSkip() {
   840  		defer func() {
   841  			if r := recover(); r != nil {
   842  				defer debug.PrintStack()
   843  				t.Skip(r)
   844  			}
   845  		}()
   846  	}
   847  	fname := strings.ReplaceAll(c.name, " ", "_") + ".c"
   848  	var srcs []cc.Source
   849  	if c.inc != "" {
   850  		srcs = append(srcs, cc.Source{
   851  			Name:  strings.TrimSuffix(fname, ".c") + "_predef.h",
   852  			Value: c.inc,
   853  		})
   854  	}
   855  	srcs = append(srcs, cc.Source{
   856  		Name:  fname,
   857  		Value: c.src,
   858  	})
   859  	econf := types.Config32()
   860  	for _, f := range c.envFuncs {
   861  		f(&econf)
   862  	}
   863  	env := libs.NewEnv(econf)
   864  	ast, err := ParseSource(env, ParseConfig{
   865  		WorkDir:    "",
   866  		Predefines: c.builtins,
   867  		Sources:    srcs,
   868  	})
   869  	if c.skip {
   870  		t.SkipNow()
   871  	} else {
   872  		require.NoError(t, err)
   873  	}
   874  
   875  	tconf := Config{ForwardDecl: true}
   876  	for _, f := range c.configFuncs {
   877  		f(&tconf)
   878  	}
   879  	decls, err := TranslateAST(fname, ast, env, tconf)
   880  	require.NoError(t, err)
   881  
   882  	buf := bytes.NewBuffer(nil)
   883  	err = PrintGo(buf, testPkg, decls)
   884  	assert.NoError(t, err)
   885  
   886  	exp := c.exp
   887  	a, b := strings.TrimSpace(exp), strings.TrimSpace(strings.TrimPrefix(buf.String(), "package lib"))
   888  	if a != b {
   889  		if c.skipExp != "" {
   890  			a = strings.TrimSpace(c.skipExp)
   891  			require.Equal(t, a, b)
   892  			t.SkipNow()
   893  		} else if c.skip {
   894  			t.SkipNow()
   895  		} else {
   896  			require.Equal(t, a, b)
   897  		}
   898  	}
   899  	if c.skip && !t.Failed() {
   900  		require.Fail(t, "skipped test passes")
   901  	}
   902  }
   903  
   904  func runTestTranslate(t *testing.T, cases []parseCase) {
   905  	for _, c := range cases {
   906  		t.Run(c.name, func(t *testing.T) {
   907  			runTestTranslateCase(t, c)
   908  		})
   909  	}
   910  }
   911  
   912  func TestTypeResolution(t *testing.T) {
   913  	const (
   914  		fname = "resolve.c"
   915  	)
   916  	env := libs.NewEnv(types.Config32())
   917  	ast, err := ParseSource(env, ParseConfig{
   918  		WorkDir: "",
   919  		Sources: []cc.Source{
   920  			//		{
   921  			//			Name: "resolve.h",
   922  			//			Value:`
   923  			//void unused(char*,int);
   924  			//`,
   925  			//		},
   926  			{
   927  				Name: fname,
   928  				Value: `
   929  typedef int int_t;
   930  int_t a, b;
   931  struct bar {
   932  	int_t x;
   933  	int_t y;
   934  };
   935  struct bar *f1(int_t c, struct bar e) {
   936  	int_t b;
   937  	int_t d = a + b + c + e.x + e.y;
   938  }
   939  `,
   940  			},
   941  		},
   942  	})
   943  	require.NoError(t, err)
   944  
   945  	decls, err := TranslateCAST(fname, ast, env, Config{})
   946  	require.NoError(t, err)
   947  	require.Len(t, decls, 5)
   948  
   949  	// find the first int typedef
   950  	d1, ok := decls[0].(*CTypeDef)
   951  	require.True(t, ok)
   952  	// check the named type that we get
   953  	intT := d1.Named
   954  	assert.Equal(t, "int_t", intT.Name().Name)
   955  	assert.Equal(t, types.IntT(4), intT.Underlying())
   956  
   957  	// both variable declarations should have exactly the same type (by pointer)
   958  	a1d, ok := decls[1].(*CVarDecl)
   959  	require.True(t, ok)
   960  	assert.Equal(t, "a", a1d.Names[0].Name)
   961  	assert.True(t, intT == a1d.Type, "invalid type in global")
   962  
   963  	b1d, ok := decls[2].(*CVarDecl)
   964  	require.True(t, ok)
   965  	assert.Equal(t, "b", b1d.Names[0].Name)
   966  	assert.True(t, intT == b1d.Type, "invalid type in global 2")
   967  
   968  	// test struct definition
   969  	bard, ok := decls[3].(*CTypeDef)
   970  	require.True(t, ok)
   971  	assert.Equal(t, "bar", bard.Name().Name)
   972  	bar, ok := bard.Underlying().(*types.StructType)
   973  	require.True(t, ok)
   974  	require.Len(t, bar.Fields(), 2)
   975  	xf := bar.Fields()[0]
   976  	yf := bar.Fields()[1]
   977  	assert.True(t, intT == xf.Type(), "invalid type in struct field 1")
   978  	assert.True(t, intT == yf.Type(), "invalid type in struct field 2")
   979  
   980  	// check that the same type works in function args
   981  	f1d, ok := decls[4].(*CFuncDecl)
   982  	require.True(t, ok)
   983  	assert.Equal(t, "f1", f1d.Name.Name)
   984  	f1t := f1d.Type
   985  	require.Len(t, f1t.Args(), 2)
   986  	assert.True(t, intT == f1t.Args()[0].Type(), "invalid type in func arg")
   987  	assert.True(t, bard.Named == f1t.Args()[1].Type(), "invalid type in func arg")
   988  	p1, ok := f1t.Return().(types.PtrType)
   989  	require.True(t, ok)
   990  	assert.True(t, bard.Named == p1.Elem(), "invalid type in func return")
   991  
   992  	require.Len(t, f1d.Body.Stmts, 3)
   993  	// first decl is always __func__
   994  	s1, ok := f1d.Body.Stmts[0].(*CDeclStmt)
   995  	require.True(t, ok)
   996  	fnc_, ok := s1.Decl.(*CVarDecl)
   997  	require.True(t, ok)
   998  	require.Equal(t, "__func__", fnc_.Names[0].Name)
   999  
  1000  	// check if the type works in function body
  1001  	s1, ok = f1d.Body.Stmts[1].(*CDeclStmt)
  1002  	require.True(t, ok)
  1003  	b2d, ok := s1.Decl.(*CVarDecl)
  1004  	require.True(t, ok)
  1005  	assert.Equal(t, "b", b2d.Names[0].Name)
  1006  	assert.True(t, intT == b2d.Type, "invalid type in local")
  1007  	// and that we can distinguish globals from locals
  1008  	assert.True(t, b1d != b2d)
  1009  	assert.True(t, b1d.Names[0] != b2d.Names[0])
  1010  
  1011  	// check same conditions for a second local decl
  1012  	s1, ok = f1d.Body.Stmts[2].(*CDeclStmt)
  1013  	require.True(t, ok)
  1014  	d1d, ok := s1.Decl.(*CVarDecl)
  1015  	require.True(t, ok)
  1016  	assert.Equal(t, "d", d1d.Names[0].Name)
  1017  	assert.True(t, intT == d1d.Type, "invalid type in local 2")
  1018  	// check variables - one is global, second is local, third is an arg
  1019  	e1, ok := d1d.Inits[0].(*CBinaryExpr)
  1020  	require.True(t, ok, "%T", d1d.Inits[0])
  1021  	e2, ok := e1.Right.(*CSelectExpr)
  1022  	assert.True(t, ok, "%T", e1.Right)
  1023  	assert.True(t, e2.Sel == yf.Name, "invalid field ref 5")                  // arg
  1024  	assert.True(t, e2.Expr == IdentExpr{f1t.Args()[1].Name}, "invalid ref 5") // arg
  1025  
  1026  	e1, ok = e1.Left.(*CBinaryExpr)
  1027  	require.True(t, ok, "%T", e1.Left)
  1028  	e2, ok = e1.Right.(*CSelectExpr)
  1029  	assert.True(t, ok, "%T", e1.Right)
  1030  	assert.True(t, e2.Sel == xf.Name, "invalid field ref 4")                  // arg
  1031  	assert.True(t, e2.Expr == IdentExpr{f1t.Args()[1].Name}, "invalid ref 4") // arg
  1032  
  1033  	e1, ok = e1.Left.(*CBinaryExpr)
  1034  	require.True(t, ok, "%T", e1.Left)
  1035  	assert.True(t, IdentExpr{f1t.Args()[0].Name} == e1.Right, "invalid ref 3") // arg
  1036  
  1037  	e1, ok = e1.Left.(*CBinaryExpr)
  1038  	require.True(t, ok)
  1039  	assert.True(t, IdentExpr{a1d.Names[0]} == e1.Left, "invalid ref 1")  // global
  1040  	assert.True(t, IdentExpr{b2d.Names[0]} == e1.Right, "invalid ref 2") // local
  1041  }