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